All source code for this blog is from JDK 1.8
Cyclicbarrier, a synchronous helper class, is described in the API:
It allows a group of threads to wait for each other until a common barrier point (common barrier points) is reached. In programs that involve a set of fixed-size threads, these threads have to wait for each other, and cyclicbarrier is useful at this time. Because the barrier can be reused after releasing the waiting thread, it is called a cyclic barrier.
In layman's words, a set of threads is blocked when it reaches a barrier, and the barrier opens when the last thread reaches the barrier, and all the threads that are blocked by the barrier will continue to work.
Implementation analysis
The structure of the Cyclicbarrier is as follows:
Through we can see that the inside of the Cyclicbarrier is using the re-entry lock reentrantlock and condition. It has two constructors:
Cyclicbarrier (int Parties): Creates a new cyclicbarrier that starts when a given number of participants (threads) are waiting, but does not perform a predefined operation when the barrier is started.
Cyclicbarrier (int parties, Runnable barrieraction): Creates a new cyclicbarrier that starts when a given number of participants (threads) are waiting and starts barrier Performs a given barrier operation, which is performed by the last thread that enters barrier.
Parties indicates the number of blocked threads.
The runnable command received by Barrieraction for Cyclicbarrier, used to prioritize barrieraction when the thread arrives at the barrier, to handle more complex business scenarios.
publicCyclicBarrier(int parties, Runnable barrierAction) { if0thrownew IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction; } publicCyclicBarrier(int parties) { thisnull); }
The most important method in Cyclicbarrier is that the await () method waits until all the participants have already barrier the await method. As follows:
publicintawaitthrows InterruptedException, BrokenBarrierException { try { return dowait(false0L);//不超时等待 catch (TimeoutException toe) { thrownew// cannot happen } }
The await () method internally calls the Dowait (Boolean timed, Long Nanos) method:
Private int dowait(BooleanTimedLongNanosthrowsInterruptedexception, Brokenbarrierexception, timeoutexception {//Get lock FinalReentrantlock lock = This. Lock; Lock.lock ();Try{//Generational FinalGeneration g = Generation;//Current generation "corrupted", throws Brokenbarrierexception exception //Throws this exception is typically a thread waiting for a cyclicbarrie that is in a "fractured" state if(G.broken)the exception is thrown when a thread attempts to wait for a barrier in the disconnected state, or if the thread is in a waiting state while the barrier enters a disconnected state Throw NewBrokenbarrierexception ();//If thread is interrupted, terminate Cyclicbarrier if(Thread.interrupted ()) {Breakbarrier ();Throw NewInterruptedexception (); }//Come in a thread count-1 intindex =--count;//count = = 0 indicates that all threads are in place, triggering runnable tasks if(Index = =0) {//Tripped BooleanRanaction =false;Try{FinalRunnable command = Barriercommand;//Trigger task if(Command! =NULL) Command.run (); Ranaction =true;//Wake up all waiting threads, and update generationNextgeneration ();return 0; }finally{if(!ranaction) Breakbarrier (); } } for(;;) {Try{//If the wait is not timed out, call the Condition.await () method to wait if(!timed) trip.await ();Else if(Nanos >0L//Timeout wait, call Condition.awaitnanos () method WaitNanos = Trip.awaitnanos (Nanos); }Catch(Interruptedexception IE) {if(g = = Generation &&! G.broken) {Breakbarrier ();ThrowKey }Else{//We ' re about-to-finish waiting even if We had not //been interrupted, so this interrupt are deemed to //"belong" to subsequent execution.Thread.CurrentThread (). interrupt (); } }if(G.broken)Throw NewBrokenbarrierexception ();//generation has been updated to return index if(g! = Generation)returnIndex//"Timeout Wait", and time has arrived, terminating Cyclicbarrier, and throwing an exception if(Timed && Nanos <=0L) {breakbarrier ();Throw NewTimeoutException (); } } }finally{//Release lockLock.unlock (); } }
In fact, the processing logic of await () is relatively simple: if the thread is not the last thread to arrive, then he will be waiting until the following happens:
- Last thread arrives, that is, index = = 0
- Specified time Exceeded (timeout wait)
- One of the other threads interrupts the current thread
- One of the other threads interrupts another waiting thread
- One of the other threads is waiting for barrier to time out
- One of the other threads calls the Reset () method in this barrier. The Reset () method is used to reset the barrier to its initial state.
In the above source code, we may need to pay attention to the generation object, in the above code we can always see the throw brokenbarrierexception exception, then when to throw an exception? Throws a Brokenbarrierexception exception if a thread is waiting, if another thread calls reset (), or if the calling barrier is originally corrupted. At the same time, when any thread is interrupted while waiting, all other threads will throw a brokenbarrierexception exception and put barrier in a corrupt state.
At the same time, generation describes the more obvious replacement of Cyclicbarrier. In Cyclicbarrier, the same batch of threads belongs to the same generation. When a parties thread arrives at Barrier,generation, it will be replaced by a replacement. Where broken identifies if the current cyclicbarrier is already in a broken state.
privatestaticclass Generation { booleanfalse; }
The default barrier is not corrupted.
When barrier is damaged or one thread is interrupted, all threads are terminated by Breakbarrier ():
privatevoidbreakBarrier() { true; count = parties; trip.signalAll(); }
In addition to setting broken to true in Breakbarrier (), Signalall will also be called to wake all the threads in the Cyclicbarrier waiting state.
When all the threads have reached barrier (index = = 0), the update is done through Nextgeneration (), and in this step, there are three things to do: Wake up all the threads and reset the count,generation.
privatevoidnextGeneration() { trip.signalAll(); count = parties; new Generation(); }
Cyclicbarrier also provides an await (long timeout, Timeunit unit) method for timeout control, internally or by calling Doawait ().
Application Scenarios
Cyclicbarrier the combined operation with multi-threaded results for multithreaded computing data, and finally the application scenario for merging the results. For example, we need to count the data in multiple Excel and wait for a total result. We can process each Excel through multithreading, get the corresponding result after executing, finally calculate the result of these threads by Barrieraction, get the sum of all Excel.
Application examples
For example, we can only meet when all the people are in the meeting, as follows:
Public class cyclicbarriertest { Private StaticCyclicbarrier Cyclicbarrier;StaticClass Cyclicbarrierthread extends thread{ Public void Run() {System.out.println (Thread.CurrentThread (). GetName () +"It's here.");//Wait Try{cyclicbarrier.await (); }Catch(Exception e) {E.printstacktrace (); } } } Public Static void Main(string[] args) {Cyclicbarrier =NewCyclicbarrier (5,NewRunnable () {@Override Public void Run() {System.out.println ("The man is here, the meeting is over ...."); } }); for(inti =0; I <5; i++) {NewCyclicbarrierthread (). Start (); } }}
Operation Result:
"Dead java Concurrency"-----j.u.c's Concurrency tool class: Cyclicbarrier