11

一个看似简单的问题:我有一个java.util.concurrent.Semaphore,并且我想使用acquire().

如果线程被中断,则指定该acquire()方法抛出:InterruptedException

如果当前线程:

  • 在进入此方法时设置其中断状态;或者
  • 在等待许可时被打断,

然后抛出 InterruptedException 并清除当前线程的中断状态。

但是,可能抛出的方法的常见模式InterruptedException是在循环中调用它们,因为线程可能会受到看起来与被中断相同的虚假唤醒的影响。例如,文档Object.wait(long)说:

线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,如果条件不满足则继续等待。换句话说,等待应该总是在循环中发生。

那么问题来Semaphore.acquire()了,是否会受到同样的虚假唤醒?合乎逻辑的答案是“不”,但我找不到任何证据,事实上证据似乎指向另一个方向。

查看源代码Semaphore,它似乎将实际的获取委托给一个AbstractQueuedSynchronizer,根据其源代码委托给LockSupport.park().

明确提到虚假唤醒的文档LockSupport.park()AbstractQueuedSynchronizer.doAcquireInterruptably(),但似乎只是检查Thread.interrupted()然后 throw的实现InterruptedException

所以,除非我遗漏了一些东西(这很有可能),否则它似乎Semaphore.acquire() 抛出InterruptedException虚假?

那是对的吗?更重要的是,我能做些什么吗?我可以使用Semaphore.acquireUninterruptably(),但我不想要一个不间断的等待,只是一个不会被虚假中断的等待。有没有其他选择?

4

2 回答 2

7

是“虚假唤醒”而不是“虚假中断”:“一个线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。” 在虚假唤醒期间没有抛出 InterruptedException。正如您在评论中所说:线程唤醒但未设置中断标志。

于 2012-08-28T18:19:12.887 回答
3

我想如果你考虑一下Semaphore.acquire()API,你会意识到它不可能有虚假的唤醒,主要是因为调用者无法区分“虚假”和“正常”,因此该方法是无用的。

于 2012-08-28T18:24:02.707 回答