JDK-6801020 : Concurrent Semaphore release may cause some require thread not signaled
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 6u11,6u17
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_10,windows_xp
  • CPU: x86,sparc
  • Submitted: 2009-02-04
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
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 Availabitlity Release.

To download the current JDK release, click here.
JDK 7
7 b55Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_11"
Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot(TM) Client VM (build 11.0-b16, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Windows XP SP3

EXTRA RELEVANT SYSTEM CONFIGURATION :
P4 2.8HT

A DESCRIPTION OF THE PROBLEM :
Semaphore initial state 0. 4 threads run 4 tasks.
Two threads run acquire semaphore once, the other two threads run release semaphore once.
One possible result is the semaphore state value is 1 and one thread still waiting.

The possible reason:
When AbstractQueuedSynchronizer#release are called, head.waitStatus may be 0 because the previous acquire thread may run at AbstractQueuedSynchronizer#doAcquireShared before setHeadAndPropagate is called.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The given executable test case will hung. Suggest using dual-core CPU or HT CPU to reproduce.


REPRODUCIBILITY :
This bug can be reproduced occasionally.

---------- BEGIN SOURCE ----------
import java.util.concurrent.Semaphore;

public class TestSemaphore {

    private static Semaphore sem = new Semaphore(0);

    private static class Thread1 extends Thread {
        @Override
        public void run() {
            sem.acquireUninterruptibly();
        }
    }

    private static class Thread2 extends Thread {
        @Override
        public void run() {
            sem.release();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10000000; i++) {
            Thread t1 = new Thread1();
            Thread t2 = new Thread1();
            Thread t3 = new Thread2();
            Thread t4 = new Thread2();
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t1.join();
            t2.join();
            t3.join();
            t4.join();
            System.out.println(i);
        }
    }
}

---------- END SOURCE ----------

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/tl/jdk/rev/5303aece2068
2010-01-13

EVALUATION There was a race condition that could prevent a releaseShared from being propagated through to a parked thread, leaving the thread parked while a permit existed. Fix supplied by Doug Lea, and Martin Buccholz.
2009-03-31

PUBLIC COMMENTS Also reproduces on JDK 7.
2009-02-05

PUBLIC COMMENTS [Edited because bug has now reproduced on 6u11.] I can reproduce this easily on JDK5u16 and less readily on JDK 6u11. I don't see any fixed bugs that are definitely related to this but 6241823 might be. I modified the test program a little to show the Semaphore state when it gets stuck. import java.util.concurrent.Semaphore; public class TestSemaphore { private static Semaphore sem = new Semaphore(0); private static class Blocker extends Thread { @Override public void run() { sem.acquireUninterruptibly(); } } private static class Signaller extends Thread { @Override public void run() { sem.release(); } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10000000; i++) { Thread b1 = new Blocker(); Thread b2 = new Blocker(); Thread t3 = new Signaller(); Thread t4 = new Signaller(); b1.start(); b2.start(); t3.start(); t4.start(); waitFor(b1); waitFor(b2); t3.join(); t4.join(); System.out.println(i); } } static void waitFor(Thread t) throws InterruptedException { t.join(30 * 1000); if (t.isAlive()) { System.out.printf("Semaphore stuck: permits %d, thread waiting %s%n", sem.availablePermits(), sem.hasQueuedThreads() ? "true" : "false"); System.exit(-1); } } }
2009-02-05