由于虚假的唤醒,Semaphore.acquire()会抛出InterruptedException吗?

时间:2012-08-28 18:09:09

标签: java semaphore java.util.concurrent

一个看似简单的问题:我有一个java.util.concurrent.Semaphore,我希望使用acquire()获得许可。

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

  

如果是当前帖子:

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

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

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

  

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

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

查看source for Semaphore,它似乎将实际获取权委托给AbstractQueuedSynchronizer,根据its source委托给LockSupport.park()

documentation for LockSupport.park()明确提到虚假唤醒,但AbstractQueuedSynchronizer.doAcquireInterruptably()的实施似乎只是检查Thread.interrupted()然后抛出InterruptedException

所以,除非我遗漏某些内容(这是非常可能的),Semaphore.acquire() 可能会虚假地抛出InterruptedException

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

2 个答案:

答案 0 :(得分:7)

这是"虚假的唤醒"不是"虚假中断":"线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒。"在虚假唤醒期间没有抛出InterruptedException。正如你在评论中所说:线程醒来但是没有设置中断的标志。

答案 1 :(得分:2)

我认为如果你考虑Semaphore.acquire() API,你会发现它不可能有一个虚假的唤醒,主要是因为调用者没有办法区分“假”为“正常”,因此该方法将无用