This talk cyclicbarrier fence, as can be seen from its name, it is reusable.
It functions like a countdownlatch category, and also lets a group of threads wait and start running down. But there are some differences between the two
1. Different objects and so on. The Countdownlatch group thread waits for an event. Or the event that a counter belongs to 0. And cyclicbarrier waiting for the thread, only the threads are all up to run down
2. Using different methods, this is also caused by waiting for the object, Countdownlatch need to call await () to let the thread wait. Call Countdown () to change the state until the event that has a status of 0 is triggered. Cyclicbarrier only needs to invoke await () to let the thread wait, when the number of threads calling the await () method satisfies the condition. You wake up all the threads and run down
3. Cyclicbarrier is able to use its own active cycle, and when an interception is opened, it will voluntarily create the next intercept. Countdownlatch counter cannot be used again after 0
4. The underlying implementation is different, Countdownlatch uses AQS to achieve the underlying synchronization, cyclicbarrier based on the upper Reetrantlock + condition condition Queue implementation
5. The failure mechanism differs, the thread waiting in the Countdownlatch is assumed to be interrupted or timed out, without affecting other threads. and Cyclicbarrier adopts the mechanism of all-or-none, either all does not pass, or all passes. This means that once the thread waiting in the cyclicbarrier is interrupted or timed out, all other threads waiting in the cyclicbarrier are woken up and run down the fence.
6. Cyclicbarrier supports all threads passing through the callback function, passing in a Runnable object. Run by the last thread that arrives. And Countdownlatch does not support callback mechanisms
Here's a look at Cyclicbarrier's source code, which has an internal class generation to deal with the problem of recycling, maintaining a broker state that indicates whether the current fence is invalid. If it fails, the state of the fence can be reset.
When the fence is broken, set the current generation broker to true to fail, and wake up all waiting threads, the all-or-none mechanism
private static Class Generation { Boolean broken = false; } private void Nextgeneration () {//Signal completion of last generation Trip.signalall (); Set up next generation count = parties; Generation = new Generation (); }private void Breakbarrier () {Generation.broken = true; Count = parties; Trip.signalall (); }
Maintains a reentrantlock to synchronize. and creates a related conditional queue condition, using the condition await () method to have the thread wait in the same condition queue. Use Condition.signalall () to wake all threads waiting through a conditional queue.
/** the lock for guarding barrier entry * /private final reentrantlock lock = new Reentrantlock (); /** Condition to wait on until tripped * /private final Condition trip = Lock.newcondition ();
Maintains a runnable to support callback functions
/* The command to run when tripped * /private final Runnable barriercommand;public cyclicbarrier (int parties, Runnable Barrieraction) {if (parties <= 0) throw new IllegalArgumentException (); This.parties = parties; This.count = parties; This.barriercommand = barrieraction; }
A count is maintained to count when the await () method is called once, and Count is reduced by 1 until count is 0 to open the fence.
private int count;
You can see that the instance properties of Cyclicbarrier are not using volatile variables. So how does it guarantee the visibility of the state? The cyclicbarrier uses the Ga Xian-lock method. We know that explicit and built-in locks guarantee visibility, ordering, and atomicity.
1. Enter the lock equivalent to read volatile, will empty the CPU cache, forcing read from memory
2. Leave the lock equivalent to write volatile, the CPU write buffer data will be forced to flush to memory
Cyclicbarrier often use support for common waits and time-limited waits. Finally, the Dowait () method is dropped.
public int await () throws Interruptedexception, Brokenbarrierexception { try { return dowait (false, 0L); } catch (timeoutexception toe) { throw new Error (toe);//cannot happen; } } public int await (long timeout, timeunit unit) throws Interruptedexception, Brokenbarrierexception, timeoutexception {return dowait (true, Unit.tonanos (timeout)); }
Look at the Dowait method.
1. Locks must be acquired first to ensure visibility, ordering, atomicity
2. Infer the status of the current fence, assuming that it has failed, throw brokerbarrierexception exception
3. Assume that the thread is interrupted. So if the fence fails, it wakes up all the waiting threads to run down.
4. Run one time dowait to count minus one, use index to record the current thread as the count value to run as indexes
5. Assume that index = = 0 is the last thread to be reached and can open the fence. First assume that there is a callback. The callback is run. Then reset the fence state so that it can be recycled, returning 0
6. Assuming that index is not 0, indicating that it is not the last thread to arrive, polling waits, where the time-limited operation is supported, using the await () mechanism of the condition conditional queue. Until the time-out or the fence is normally invalidated. When a fence fails, it uses condition to wake all the threads waiting in the same condition queue.
private int Dowait (Boolean timed, Long Nanos) throws Interruptedexception, Brokenbarrierexception, Ti meoutexception {final Reentrantlock lock = This.lock; Lock.lock (); try {final Generation g = Generation; if (g.broken) throw new Brokenbarrierexception (); if (thread.interrupted ()) {breakbarrier (); throw new Interruptedexception (); } int index =--count; if (index = = 0) {//tripped Boolean ranaction = false; try {final Runnable command = Barriercommand; if (command! = null) Command.run (); Ranaction = true; Nextgeneration (); return 0; } finally {if (!ranaction) breakbarrier (); }}//loop until tripped, BrokEn, interrupted, or timed out for (;;) {try {if (!timed) trip.await (); else if (Nanos > 0L) Nanos = Trip.awaitnanos (Nanos); } catch (Interruptedexception IE) {if (g = = Generation &&! G.broken) { Breakbarrier (); throw ie; } else {//we ' re about-to-finish waiting even if We had not//been Interru Pted, so this interrupt are deemed to//"belong" to subsequent execution. Thread.CurrentThread (). interrupt (); }} if (G.broken) throw new Brokenbarrierexception (); if (g! = generation) return index; If (timed && Nanos <= 0L) {breakbarrier (); throw new TimeoutException (); }}} finally {Lock.unlock (); } }
The following is a test example to measure the function of Cyclicbarrier
1. Create a 5-capacity cyclicbarrier and set the callback
2. Execution of 12 threads
Package Com.lock.test;import Java.util.concurrent.cyclicbarrier;public class Cyclicbarrierusecase {private Cyclicbarrier barrier = new Cyclicbarrier (5, new Runnable () {@Overridepublic void run () {System.out.println ("Callback is R Unning ");}); public void Race () throws Exception{system.out.println ("Thread" + thread.currentthread (). GetName () + ' is waiting the res Ource "); barrier.await (); System.out.println ("Thread" + thread.currentthread (). GetName () + "got the Resource");} public static void Main (string[] args) {final cyclicbarrierusecase usecase = new Cyclicbarrierusecase (); for (int i = 0; I &l T 12; i++) {Thread t = new Thread (new Runnable () {@Overridepublic void run () {try {usecase.race ()} catch (Exception e) {//TODO A Uto-generated catch Blocke.printstacktrace ();}}, String.valueof (i)); T.start ();}}}
Test results:
1. Be able to see 5 threads waiting. Until the full 5 threads arrive and open the fence, the 5 threads run down and the callbacks run
2. The fence is recycled. Another 5 threads are waiting. Until the full 5 threads arrive and open the fence to run down. and run the callback
3. The fence is recycled, but only 2 threads, less than 5, have been waiting
Thread 0 is waiting the Resourcethread 4 is waiting the Resourcethread 5 are waiting the Resourcethread 3 is waiting the RE Sourcethread 2 is waiting the Resourcecallback are Runningthread 1 is waiting the Resourcethread 0 got the Resourcethread 2 Got the Resourcethread 6 is waiting the Resourcethread 7 are waiting the Resourcethread 4 got the Resourcethread 9 is wait ing the Resourcethread 8 is waiting the Resourcethread 3 got the Resourcethread 5 got the Resourcecallback is Runningthrea D 8 got the Resourcethread 1 got the Resourcethread 7 got the Resourcethread 6 got the Resourcethread is waiting the RE Sourcethread waiting the Resourcethread 9 got the resource
Copyright notice: This article blog original article. Blogs, without consent, may not be reproduced.
Talking about high concurrency (30) parsing java.util.concurrent various components (12) Understanding cyclicbarrier Fence