JDK-6384064 : SynchronousQueue put/take interrupt handling differs from timed poll
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2006-02-10
  • Updated: 2010-04-02
  • Resolved: 2006-02-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b73Fixed
Related Reports
Relates :  
Description
A DESCRIPTION OF THE REGRESSION :
The interrupted status of the current thread is no longer cleared when the InterruptedException is thrown during a put or take from the SynchronousQueue.  Even though the interruption behavior is not specified in the documentation, the behavior should be consistent across the methods of the class (or better yet the entire JDK).


REPRODUCIBLE TESTCASE OR STEPS TO REPRODUCE:
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

public class ExchangeTest {
  public static void main(final String[] args) throws InterruptedException {
    final SynchronousQueue meeting = new SynchronousQueue();
    Thread other = new Thread() {
      public void run() {
        try {
          meeting.put(args);
        }
        catch(InterruptedException IE) {
          System.out.println("Interrupt status for put set? "+ Thread.interrupted());
        }

        try {
          meeting.take();
        }
        catch(InterruptedException IE) {
          System.out.println("Interrupt status for take set? "+ Thread.interrupted());
        }

        try {
          meeting.offer(args, 60, TimeUnit.SECONDS);
        }
        catch(InterruptedException IE) {
          System.out.println("Interrupt status for offer set? "+ Thread.interrupted());
        }
        
        try {
          meeting.poll(60, TimeUnit.SECONDS);
        }
        catch(InterruptedException IE) {
          System.out.println("Interrupt status for poll set? "+ Thread.interrupted());
        }
      }
    };

    other.start();
    
    other.join(1000);
    other.interrupt();

    other.join(1000);
    other.interrupt();
    
    other.join(1000);
    other.interrupt();
    
    other.join(1000);
    other.interrupt();
    other.join();
  }
}

RELEASE LAST WORKED:
5.0 Update 6

RELEASE TEST FAILS:
mustang-b70

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Interrupt status for put set? false
Interrupt status for take set? false
Interrupt status for offer set? false
Interrupt status for poll set? false
ACTUAL -
Interrupt status for put set? true
Interrupt status for take set? true
Interrupt status for offer set? false
Interrupt status for poll set? false

OBSERVED APPLICATION IMPACT:
Most of my applications only expect the interrupted status to be set inside the InterruptedException catch block when a user request the application to be shutdown.  For example, the running task is interrupted via Future.cancel(true) followed by ExecutorService.shutdownNow() when the exit signal is received.  Since the program is in shutdown, the user interface is not updated to allow the application thread to exit sooner.
If the interrupted status remains after the InterruptedException is thrown, the program has no way to tell the difference between a user canceling a task vs. the user requesting a shutdown.

Release Regression From : 5.0
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

Comments
EVALUATION The submitter is a stellar bug finder. Doug Lea writes: "Good catch! Thread.interrupted() needs to be called to ensure that the interrupt being reported is cleared on return."
11-02-2006

SUGGESTED FIX --- /tmp/geta27410 2006-02-10 16:20:27.694047000 -0800 +++ SynchronousQueue.java 2006-02-10 16:18:12.492257000 -0800 @@ -803,16 +803,18 @@ * another thread to receive it. * * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void put(E o) throws InterruptedException { if (o == null) throw new NullPointerException(); - if (transferer.transfer(o, false, 0) == null) + if (transferer.transfer(o, false, 0) == null) { + Thread.interrupted(); throw new InterruptedException(); + } } /** * Inserts the specified element into this queue, waiting if necessary * up to the specified wait time for another thread to receive it. * * @return <tt>true</tt> if successful, or <tt>false</tt> if the @@ -851,14 +853,15 @@ * @return the head of this queue * @throws InterruptedException {@inheritDoc} */ public E take() throws InterruptedException { Object e = transferer.transfer(null, false, 0); if (e != null) return (E)e; + Thread.interrupted(); throw new InterruptedException(); } /** * Retrieves and removes the head of this queue, waiting * if necessary up to the specified wait time, for another thread * to insert it.
10-02-2006

EVALUATION Looks like a bug introduced by 6264015: Performance improvement to Exchanger and SynchronousQueue in mustang build 51.
10-02-2006