我正在使用教程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());
}
如果我注释executorService.shutdown();在上述测试用例摘要中,则测试失败并显示以下错误.
06001
一旦删除评论并启用executorService.shutdown();测试工作正常.
我不明白测试(信号灯可用许可)如何取决于外部线程池.另外,当我没有释放任何许可证时,如何使用1个插槽?任何简短的解释都会有所帮助.提前致谢.
解决方法:
这是一致的行为,还是有时您获得的Actual值不同(省略executorService.shutdown()调用时)?如果您偶尔看到其他值(例如2或3),则强烈暗示这全是由于调度/定时造成的.
尝试用Thread.sleep(15_000)替换executorService.shutdown().如果进行此更改,测试是否通过?如果是,则表明发生的事情是执行shutdown()调用所需的额外时间足以确保可以派生10个线程并执行其工作(调用tryLogin()来减少信号量) ),然后执行assertEquals()调用.请注意,按照documentation,shutdown()启动ExecutorService的有序关闭,因为它可以使执行任务运行到完成状态,但是在此期间调用本身不会阻塞.结果,执行shutdown()所需的时间恰好足以允许其他线程终止,这似乎完全是偶然的.因此,这不是一个很好的测试,因为该行为在不同的机器上可能会有所不同.相反,测试应该先调用shutdown(),再调用awaitTermination()(或使用由工作程序递减的CountDownLatch以阻止主线程),以确保直到所有工作程序线程终止后才执行assertEquals()调用. .