简体   繁体   English

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

[英]Can Semaphore.acquire() throw InterruptedException due to a spurious wakeup?

A seemingly straightforward problem: I have a java.util.concurrent.Semaphore , and I want to acquire a permit using acquire() . 一个看似简单的问题:我有一个java.util.concurrent.Semaphore ,我想使用acquire()获取许可证。

The acquire() method is specified to throw InterruptedException if the thread is interrupted: 如果线程被中断,则指定acquire()方法抛出InterruptedException

If the current thread: 如果当前线程:

  • has its interrupted status set on entry to this method; 在进入此方法时设置其中断状态; or 要么
  • is interrupted while waiting for a permit, 在等待许可证时被打断,

then InterruptedException is thrown and the current thread's interrupted status is cleared. 然后抛出InterruptedException并清除当前线程的中断状态。

However, the usual pattern with methods that may throw InterruptedException is to call them in a loop, since threads can be subject to spurious wakeups that look the same as being interrupted. 但是,使用可能抛出InterruptedException方法的通常模式是在循环中调用它们,因为线程可能会受到与被中断相同的虚假唤醒。 For example, the documentation for Object.wait(long) says: 例如, Object.wait(long)文档说:

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. 线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒。 While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. 虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,并且如果条件不满足则继续等待。 In other words, waits should always occur in loops. 换句话说,等待应始终在循环中进行。

So the question is, is Semaphore.acquire() subject to the same kind of spurious wakeup? 所以问题是, Semaphore.acquire()受到同样的虚假唤醒? The logical answer would be "no", but I can't find any evidence for that, and in fact the evidence seems to point in the other direction. 合乎逻辑的答案是“不”,但我找不到任何证据,实际上证据似乎指向了另一个方向。

Looking at the source for Semaphore , it appears that it delegates the actual acquire to an AbstractQueuedSynchronizer , which according to its source delegates to LockSupport.park() . 查看Semaphore源代码 ,它似乎将实际的获取委托给一个AbstractQueuedSynchronizer ,根据它的源委托给LockSupport.park()

The documentation for LockSupport.park() explicitly mentions spurious wakeup, but the implementation of AbstractQueuedSynchronizer.doAcquireInterruptably() appears to just check Thread.interrupted() and then throw InterruptedException . LockSupport.park()文档明确提到了虚假唤醒,但AbstractQueuedSynchronizer.doAcquireInterruptably()的实现似乎只是检查Thread.interrupted()然后抛出InterruptedException

So, unless I'm missing something (which is very possible), it appears that Semaphore.acquire() can throw InterruptedException spuriously? 所以,除非我遗漏了某些东西(这很可能),看来Semaphore.acquire() 可以虚假地抛出InterruptedException

Is that correct? 那是对的吗? More importantly, is there anything I can do about that? 更重要的是,我能做些什么吗? I could use Semaphore.acquireUninterruptably() , but I don't want an uninterruptable wait, just one that doesn't get interrupted spuriously. 我可以使用Semaphore.acquireUninterruptably() ,但我不想要一个不间断的等待,只是一个不会被虚假中断的。 Is there any alternative? 还有其他选择吗?

It is "spurious wakeup" not "spurious interrupt": "A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup." 它是“虚假唤醒”而非“虚假中断”:“线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒。” There is no InterruptedException thrown during a spurious wakeup. 在虚假唤醒期间没有抛出InterruptedException。 As you say in the comments: The thread wakes up but the interrupted flag is not set. 正如你在评论中所说:线程醒来但是没有设置中断的标志。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM