JDK-6253848 : CyclicBarrier behavior incorrect if "broken" or reset
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-04-12
  • Updated: 2010-04-02
  • Resolved: 2005-04-30
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.
Other JDK 6
5.0u6Fixed 6 b35Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
In this seemingly appropriate usage of CyclicBarrier:

* Create barrier with n + 1 parties: 1 for each "worker" thread, plus 1 for the current thread; and set a barrier action on it.
1. Start n workers, which: each perform some task and then await the barrier.
2. Have the current then thread await the barrier -- and therefore each worker, plus the barrier action.
3. Now that await has returned in the current thread, reset the barrier and run another cycle on it as above.

At the point when reset is called by the current thread, an arbitrary number (sometimes 0) of worker threads throw a BrokenBarrierException.

The await method is the only way to get notice that all parties have reported and the barrier action is also complete, but it does not behave correctly: Though the await method has returned, indicating all parties and the barrier action are complete, some parties still sense the ensuing call to reset() and throw an exception as though they had not yet completed. The reset method does not synchronize itself.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
A test case is given.


REPRODUCIBILITY :
This bug can be reproduced always.

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


public class Test {
    
    /* The number of worker threads to create: */
    private static final int WORKER_COUNT = 10;
    
    /* The barrier; with 1 party for each worker, plus the primordial thread: */
    private static final CyclicBarrier barrier
            = new CyclicBarrier((WORKER_COUNT + 1), new BarrierAction());

    
    /** A worker thread that would work on a single element of data. */
    private static class Worker extends Thread {
        public void run() {
            System.out.println(getName() + " Worker.run().");
            try {
                barrier.await();
            }
            catch (Exception ex) {
                System.err.println(" Worker terminating with exception:");
                ex.printStackTrace();
            }
        }
    }

    
    /** The action that would coordinate each Worker thread's results. */
    private static class BarrierAction implements Runnable {
        public void run() {
            System.out.println("BarrierAction.run().");
        }
    }


    /** Runs the test. Several iterations are performed on the barrier. */
    public static void main(final String[] args) throws Exception {
        /* Run more than 2 cycles on the barrier to increase
         * the likelihood of seeing an exception: */
        final int BARRIER_CYCLES = 3;
        for (int i = 0; i < BARRIER_CYCLES; i++) {
            /* Create and start workers: */
            for (int j = 0; j < WORKER_COUNT; j++) {
                new Worker().start();
            }
            
            /* Wait for all workers (plus the barrier action) to complete: */
            barrier.await();
            
            System.out.println("Barrier cycle " + i + " complete.");
            
            /* Reset for next cycle: */
            barrier.reset();
        }
    }
    
}

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

CUSTOMER SUBMITTED WORKAROUND :
You may be able to use a latch instead (assuming it works correctly). Otherwise, manually synchronize the worker threads around the call to reset -- basically manually implement the barrier on your own really. Or use something tangential like a synchronized queue.
###@###.### 2005-04-12 09:39:06 GMT

Comments
EVALUATION The JSR166 expert group is thinking about CyclicBarrier.reset() ###@###.### 2005-04-19 01:21:11 GMT There were more bugs lurking in the code: - getNumberWaiting() returned non-zero when the barrier is broken. - the barrier was not broken after the barrier action threw an exception ###@###.### 2005-04-22 03:49:37 GMT
19-04-2005