Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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().

The acquire() method is specified to throw InterruptedException if the thread is interrupted:

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.

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. For example, the documentation for Object.wait(long) says:

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? 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().

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.

So, unless I'm missing something (which is very possible), it appears that Semaphore.acquire() can throw InterruptedException spuriously?

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. Is there any alternative?

like image 245
Daniel Pryden Avatar asked Aug 28 '12 18:08

Daniel Pryden


2 Answers

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. As you say in the comments: The thread wakes up but the interrupted flag is not set.

like image 79
Skip Head Avatar answered Oct 19 '22 23:10

Skip Head


I think if you think about the Semaphore.acquire() API, you'll realize that it's impossible for it to have a spurious wakeup, mainly because the caller would have no way to distinguish "spurious" for "normal", and therefore the method would be useless.

like image 25
jtahlborn Avatar answered Oct 20 '22 01:10

jtahlborn