FULL PRODUCT VERSION :
java version " 1.7.0_21 "
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Here are the javadocs for BlockingQueue.poll(long timeout, TimeUnit unit):
/**
* Retrieves and removes the head of this queue, waiting up to the
* specified wait time if necessary for an element to become available.
*
* @param timeout how long to wait before giving up, in units of
* <tt>unit</tt>
* @param unit a <tt>TimeUnit</tt> determining how to interpret the
* <tt>timeout</tt> parameter
* @return the head of this queue, or <tt>null</tt> if the
* specified waiting time elapses before an element is available
* @throws InterruptedException if interrupted while waiting
*/
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
In particular, note that the contract on throws InterruptedException
if interrupted while waiting
HAS NO QUALIFICATION. So, anyone reading this naturally thinks that a waiting thread should always be able to be broken from waiting if it is interrupted.
Claim: this contract can be violated by ArrayBlockingQueue.
Justification: from the jdk 1.7 source code, I see that ArrayBlockingQueue.poll(long timeout, TimeUnit unit) only waits on the queue if it hits line #389:
nanos = notEmpty.awaitNanos(nanos);
The notEmpty field is a Condition instance that is created from the lock field on line #228 in a constructor:
notEmpty = lock.newCondition();
The Condition.awaitNanos javadocs, however, QUALIFY the conditions under which throws InterruptedException will occur:
/**
* ...
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of thread suspension is supported; or
* ...
* <p>If the current thread:
* ...
* <li>is {@linkplain Thread#interrupt interrupted} while waiting
* and interruption of thread suspension is supported,
* ...
* @throws InterruptedException if the current thread is interrupted
* (and interruption of thread suspension is supported)
*/
long awaitNanos(long nanosTimeout) throws InterruptedException;
So, it sound like from Condition that an InterruptedException is NOT always guaranteed to be thrown by a waiting thread that gets interrupted after all. It looks like it depends entirely on the platform's support for " interruption of thread suspension " . We are given no guidance as to what platoforms have this feature, and which ones don't. I did a web search just now, and found nothing.
Implications: while I have identified one concrete case above of the bug, I suspect that there are many more similar cases, both in other ArrayBlockingQueue methods, as well as other classes. I bet this bug is pervasive.
Solutions: you must either fix ArrayBlockingQueue.poll to satisfy the current BlockingQueue.poll contract, or else you can simply modify the BlockingQueue.poll contract to have the same qualification that ArrayBlockingQueue.poll is actually currently subject to, namely, that
* @throws InterruptedException if interrupted while waiting
* (and interruption of thread suspension is supported)
REPRODUCIBILITY :
This bug can be reproduced always.
java version " 1.7.0_21 "
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Here are the javadocs for BlockingQueue.poll(long timeout, TimeUnit unit):
/**
* Retrieves and removes the head of this queue, waiting up to the
* specified wait time if necessary for an element to become available.
*
* @param timeout how long to wait before giving up, in units of
* <tt>unit</tt>
* @param unit a <tt>TimeUnit</tt> determining how to interpret the
* <tt>timeout</tt> parameter
* @return the head of this queue, or <tt>null</tt> if the
* specified waiting time elapses before an element is available
* @throws InterruptedException if interrupted while waiting
*/
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
In particular, note that the contract on throws InterruptedException
if interrupted while waiting
HAS NO QUALIFICATION. So, anyone reading this naturally thinks that a waiting thread should always be able to be broken from waiting if it is interrupted.
Claim: this contract can be violated by ArrayBlockingQueue.
Justification: from the jdk 1.7 source code, I see that ArrayBlockingQueue.poll(long timeout, TimeUnit unit) only waits on the queue if it hits line #389:
nanos = notEmpty.awaitNanos(nanos);
The notEmpty field is a Condition instance that is created from the lock field on line #228 in a constructor:
notEmpty = lock.newCondition();
The Condition.awaitNanos javadocs, however, QUALIFY the conditions under which throws InterruptedException will occur:
/**
* ...
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of thread suspension is supported; or
* ...
* <p>If the current thread:
* ...
* <li>is {@linkplain Thread#interrupt interrupted} while waiting
* and interruption of thread suspension is supported,
* ...
* @throws InterruptedException if the current thread is interrupted
* (and interruption of thread suspension is supported)
*/
long awaitNanos(long nanosTimeout) throws InterruptedException;
So, it sound like from Condition that an InterruptedException is NOT always guaranteed to be thrown by a waiting thread that gets interrupted after all. It looks like it depends entirely on the platform's support for " interruption of thread suspension " . We are given no guidance as to what platoforms have this feature, and which ones don't. I did a web search just now, and found nothing.
Implications: while I have identified one concrete case above of the bug, I suspect that there are many more similar cases, both in other ArrayBlockingQueue methods, as well as other classes. I bet this bug is pervasive.
Solutions: you must either fix ArrayBlockingQueue.poll to satisfy the current BlockingQueue.poll contract, or else you can simply modify the BlockingQueue.poll contract to have the same qualification that ArrayBlockingQueue.poll is actually currently subject to, namely, that
* @throws InterruptedException if interrupted while waiting
* (and interruption of thread suspension is supported)
REPRODUCIBILITY :
This bug can be reproduced always.
- duplicates
-
JDK-8016283 ArrayBlockingQueue throws Interrupted Exception when it shouldn't
-
- Open
-