【发布时间】:2018-08-31 04:41:54
【问题描述】:
我正在使用教程 https://www.baeldung.com/java-semaphore 学习 Java 中的信号量。
本教程中的第一个测试(低于一个)运行良好。
@Test
public void givenLoginQueue_whenReachLimit_thenBlocked() {
int slots = 10;
ExecutorService executorService = Executors.newFixedThreadPool(slots);
LoginQueueUsingSemaphore loginQueue = new LoginQueueUsingSemaphore(slots);
IntStream.range(0, slots)
.forEach(user -> executorService.execute(loginQueue::tryLogin));
executorService.shutdown();
assertEquals(0, loginQueue.availableSlots());
assertFalse(loginQueue.tryLogin());
}
如果我在上面的测试用例 sn-p 中注释 executorService.shutdown(); 行,那么测试将失败并出现以下错误。
java.lang.AssertionError: Expected :0 Actual :1 <Click to see difference> at org.testng.AssertJUnit.fail(AssertJUnit.java:59) at org.testng.AssertJUnit.failNotEquals(AssertJUnit.java:364) at org.testng.AssertJUnit.assertEquals(AssertJUnit.java:80) at org.testng.AssertJUnit.assertEquals(AssertJUnit.java:245) at org.testng.AssertJUnit.assertEquals(AssertJUnit.java:252) at LoginQueueSemaphoreTest.givenLoginQueue_whenReachLimit_thenBlocked(LoginQueueSemaphoreTest.java:24)
一旦我删除评论并启用executorService.shutdown();,测试就会正常工作。
我无法理解测试(信号量可用许可)如何依赖于外部线程池。另外,当我没有释放任何许可证时,如何使用 1 个插槽?任何简短的解释都会有所帮助。提前致谢。
【问题讨论】:
-
这是一致的行为,还是您有时会得到不同的实际值?尝试用
Thread.sleep(15_000)替换executorService.shutdown()- 在这种情况下测试是否通过?这确实看起来很奇怪,特别是因为shutdown()不会等待提交的任务完成,但可能只是执行该调用所需的额外时间足以确保可以生成 10 个线程并在执行assertEquals()之前执行他们的工作(调用tryLogin())。 -
shutdown() does not wait for submitted tasks to finish这是错误的。 shutdownNow() 不等待,docs.oracle.com/javase/7/docs/api/java/util/concurrent/… -
@shazin 您链接的文档字面意思是“此方法不会等待先前提交的任务完成执行。使用 awaitTermination 来执行此操作。”为
shutdown()。shutdown()将启动有序关闭,即让提交的任务运行到完成,但调用本身不会阻塞。 -
@JanusVarmarken - 您的建议有效。
executorService.execute异步运行任务。添加 Thread.sleep 解决了这个问题。如果你回答了这个问题,我会接受的:)