Improving the speed of Thread interrupt checking

Charles Oliver Nutter headius at headius.com
Sat May 11 01:26:49 PDT 2013


On Sat, May 11, 2013 at 2:49 AM, Jeroen Frijters <jeroen at sumatra.nl> wrote:

> I believe Thread.interrupted() and Thread.isInterrupted() can both be
> implemented without a lock or CAS.
>
> Here are correct implementations:
>
...

> Any interrupts that happen before we clear the flag are duplicates that we
> can ignore and any that happen after are new ones that will be returned by
> a subsequent call. The key insight is that the interruptPending flag can be
> set by any thread, but it can only be cleared by the thread it applies to.
>

This may indeed be the case. My goal with considering CAS was to maintain
the full behavioral constraints of the existing implementation, which will
never clear multiple interrupts at once, regardless of duplication.

If your assumption holds, then Vitaly's case is not a concern. His case,
again:

* Thread A retrieves interrupt status
* Thread B sets interrupt, but cannot clear it from outside of thread A
* Thread A clears interrupt

The end result of this sequence is indeed different if A's get + clear are
not atomic: the interrupt status after A returns would be clear rather than
set. However, *it does not really matter*.

If we look at the *caller* of the interrupt checking, things become obvious.

Mutexed/atomic version:

* Thread A makes a call to Thread.interrupt to get and clear interrupt
status
* Thread A acquires lock and gets interrupt status and clears it atomically
* Thread A returns from Thread.interrupt, reporting that the thread was
interrupted, and the caller knows it has been cleared
* Before Thread A proceeds any further (raising an error, etc), thread B
comes in and sets interrupt status.

The result is that the interrupt is set, and there's nothing A can do to
ensure it has been cleared. A subsequent call to Thread.interrupted can be
preempted *after* the clear anyway.

So, a different preemption order with mutex:

* Thread A makes a call to Thread.interrupt to get and clear interrupt
status
* Before the mutex is acquired, Thread B swoops in, setting interrupt
status.
* Thread A proceeds to acquire mutex and only sees a single interrupt bit;
it gets status and clears it.

So even an atomic version does nothing to guarantee what the interrupt
status will be after all threads are finished fiddling with the interrupt
bit; preemption can happen before or after the mutexed operation, producing
different results in both cases.

Ultimately, this may actually be a flaw with the way Thread interrupt works
in the JVM. If there's potential for interrupt to be set twice or more, the
interrupted thread can't ever guarantee that the interrupt has been cleared.

In practice, this flaw may not matter; if you have one or more external
threads that interrupt a target thread N times, you have to assume (and
have always had to assume) the target thread will see anywhere from 1 to N
of those interrupts, depending on preemption. This does not change with any
of the proposed implementations. The only safe situation is when you know
interruption will happen only once within a critical section of code.

Put simply (tl;dr): even with atomic/mutexed interrupt set+clear, you can't
make any guarantees about how many interrupts will be seen if multiple
interrupts are attempted. If true, the mutex in the current implementation
is 100% useless.

- Charlie
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20130511/36a5df27/attachment.html 


More information about the mlvm-dev mailing list