Java Concurrency Programming: Countdownlatch, Cyclicbarrier, and semaphore
In Java 1.5, there are some very useful helper classes to help us with concurrent programming, such as Countdownlatch,cyclicbarrier and semaphore, and today we'll learn about the use of these three helper classes.
The following is an outline of this article directory:
I. Countdownlatch usage
Two. Cyclicbarrier usage
Three. Semaphore usage
If there are any shortcomings please understand, and welcome criticism.
Please respect the author's labor results, reproduced please indicate the original link:
Http://www.cnblogs.com/dolphin0520/p/3920397.html
I. Countdownlatch usage
The Countdownlatch class is located under the Java.util.concurrent package and can be used to implement similar counter functions. For example, there is a task a, which waits for the other 4 tasks to be executed before they can be executed, and this is done using Countdownlatch.
The Countdownlatch class provides only one constructor:
public Countdownlatch (int count) { }; Parameter count is a count value
Then the following 3 methods are the most important methods in the Countdownlatch class:
public void await () throws interruptedexception {}; The thread that calls the await () method is suspended, and it waits until the count value is 0 to continue executing public boolean await (long timeout, timeunit unit) throws Interruptedexception { }; Similar to await (), except for a certain amount of time after which the count value has not changed to 0 will continue to execute public void Countdown () {}; Subtract the count value by 1
Let's look at an example and see how Countdownlatch is used:
public class Test {public static void main (string[] args) { final countdownlatch latch = new Countdownlatch (2); New Thread () {public void run () {try {System.out.println ("Child Thread" +thread.currentthread (). GetName () + "executing"); Thread.Sleep (3000); SYSTEM.OUT.PRINTLN ("Child Thread" +thread.currentthread (). GetName () + "executed"); Latch.countdown (); catch (Interruptedexception e) {e.printstacktrace ();}}; }.start (); New Thread () {public void run () {try {System.out.println ("Child Thread" +thread.currentthread (). GetName () + "executing"); Thread.Sleep (3000); SYSTEM.OUT.PRINTLN ("Child Thread" +thread.currentthread (). GetName () + "execution complete"); Latch.countdown ();} catch (Interruptedexception e) {e.printstacktrace ();}}; }.start (); try {System.out.println ("Wait for 2 child threads to execute ..."); latch.await (); System.out.println ("2 sub-threads have been executed"); System.out.println ("Continue with the main thread");} catch (Interruptedexception e) {e.printstacktrace ();}} }
Execution Result:
Thread thread-0 executing threadsthread-1 executing wait 2 child threads executed ... ThreadsThread-0threads-thread-1 executes 2 sub-threads have been executed continue to execute main thread
View CodeTwo. Cyclicbarrier usage
Literally, the loopback fence, which allows a group of threads to wait until a certain state has been executed. The loopback is called because Cyclicbarrier can be reused when all waiting threads are freed. Let's call this state barrier, and when the await () method is called, the thread is barrier.
The Cyclicbarrier class is located under the Java.util.concurrent package and Cyclicbarrier provides 2 constructors:
public Cyclicbarrier (int parties, Runnable barrieraction) {}public cyclicbarrier (int parties) {}
The parameter parties refers to how many threads or tasks wait to the barrier state, and the parameter barrieraction the content that will be executed when those threads reach the barrier state.
Then the most important method in Cyclicbarrier is the await method, which has 2 overloaded versions:
public int await () throws Interruptedexception, brokenbarrierexception {};p ublic int await (long timeout, timeunit unit) th Rows Interruptedexception,brokenbarrierexception,timeoutexception {};
The first version is more commonly used to suspend the current thread until all threads reach the barrier state and perform subsequent tasks simultaneously;
The second version is to allow these threads to wait for a certain amount of time, and if the thread does not reach the barrier state, then the threads that reach barrier will perform the subsequent tasks directly.
Here are a few examples to understand:
If there are a number of threads that are going to write data, and only after all the threads have completed the write data operation, the threads can continue to do the following, and the Cyclicbarrier is now available:
public class Test {public static void main (string[] args) {int N = 4; Cyclicbarrier Barrier = new Cyclicbarrier (N); for (int i=0;i<n;i++) new Writer (barrier). Start ();} Static Class Writer extends thread{private Cyclicbarrier cyclicbarrier;public writer (cyclicbarrier Cyclicbarrier) { This.cyclicbarrier = Cyclicbarrier;} @Overridepublic void Run () {System.out.println ("thread" +thread.currentthread (). GetName () + "writing data ..."); try { Thread.Sleep (the); Use sleep to simulate the write data operation System.out.println ("Thread" +thread.currentthread (). GetName () + "write data, wait for other threads to finish writing"); Cyclicbarrier.await ();} catch (Interruptedexception e) {e.printstacktrace ();} catch (Brokenbarrierexception e) {e.printstacktrace ();} System.out.println ("All threads are finished writing, continue processing other tasks ...");}}}
Execution Result:
Thread thread-0 is writing data ... Threads Thread3 is writing data ... Threads Thread2 is writing data ... Threads thread1 is writing data ... Thread-2 writes the data, waits for another thread to finish writing the thread-0 writes the data, waits for the other thread to finish writing the thread-3 writes the data, Wait for the other thread to finish writingthe thread-1 writes the data, waits for the other thread to finish writing all the threads, and continues processing other tasks ... All threads have finished writing and continue to handle other tasks ... All threads have finished writing and continue to handle other tasks ... All threads have finished writing and continue to handle other tasks ...
View Code
As you can see from the output above, each write thread waits for another thread to write after the write operation has finished.
After all thread-thread-write operations are complete, all threads continue to perform subsequent operations.
If you want to do extra work after all the thread writes have been done, you can provide the runnable parameter for Cyclicbarrier:
public class Test {public static void main (string[] args) {int N = 4; Cyclicbarrier Barrier = new Cyclicbarrier (n,new Runnable () {@Overridepublic void run () {System.out.println ("Current thread" + Thread.CurrentThread (). GetName ());}); for (int i=0;i<n;i++) new Writer (barrier). Start ();} Static class writer extends thread{private Cyclicbarrier cyclicbarrier;public writer (cyclicbarrier Cyclicbarrier) { This.cyclicbarrier = Cyclicbarrier;} @Overridepublic void Run () {System.out.println ("thread" +thread.currentthread (). GetName () + "writing data ..."); try { Thread.Sleep (the); Use sleep to simulate the write data operation System.out.println ("Thread" +thread.currentthread (). GetName () + "write data, wait for other threads to finish writing"); Cyclicbarrier.await ();} catch (Interruptedexception e) {e.printstacktrace ();} catch (Brokenbarrierexception e) {e.printstacktrace ();} System.out.println ("All threads are finished writing, continue processing other tasks ...");}}}
Operation Result:
Thread thread-0 is writing data ... Threads thread1 is writing data ... Threads Thread2 is writing data ... Threads Thread3 is writing data ... Thread-0 writes the data, waits for another thread to finish writing the thread-1 writes the data, waits for the other thread to finish writing the thread-2 writes the data, Wait for the other thread to finish writingthe thread-3 writes the data, waits for the other thread to finish writing the current thread-3 All threads have finished writing, continue to handle other tasks ... All threads have finished writing and continue to handle other tasks ... All threads have finished writing and continue to handle other tasks ... All threads have finished writing and continue to handle other tasks ...
View Code
As you can see from the results, when four threads reach the barrier state, a thread is selected from four threads to execute the runnable.
Let's take a look at the effect of specifying the time for await:
public class Test {public static void main (string[] args) {int N = 4; Cyclicbarrier barrier = new Cyclicbarrier (N), for (int i=0;i<n;i++) {if (i<n-1) new Writer (barrier). Start (); else { try {thread.sleep;} catch (Interruptedexception e) {e.printstacktrace ();} New Writer (barrier). Start ();}}} Static class writer extends thread{private Cyclicbarrier cyclicbarrier;public writer (cyclicbarrier Cyclicbarrier) { This.cyclicbarrier = Cyclicbarrier;} @Overridepublic void Run () {System.out.println ("thread" +thread.currentthread (). GetName () + "writing data ..."); try { Thread.Sleep (5000); Use sleep to simulate the write data operation System.out.println ("Thread" +thread.currentthread (). GetName () + "write data, wait for other threads to finish writing"), try { Cyclicbarrier.await (timeunit.milliseconds);} catch (TimeoutException e) {//TODO auto-generated catch Blocke.printstacktrace ();}} catch (Interruptedexception e) {e.printstacktrace ();} catch (Brokenbarrierexception e) {e.printstacktrace ();} System.out.println (Thread.CurrentThread (). GetName () + "All threads have finished writing, continue processing other tasks ...");}}
Execution Result:
Thread thread-0 Writing data ... Threads Thread-2 Writing data ... Threads Thread-1 Writing data ... Threads Thread-2 Write the data, wait for other threads to finish writing threads thread-0 Write the data, wait for other threads to finish writing threads thread-1 Write the data, wait for other threads to finish writing threads thread-3 Writing data ... java.util.concurrent.TimeoutExceptionThread-1 Thread write completed, continue processing other tasks ... Thread-0 Threads are finished writing, continue to work on other tasks ... at java.util.concurrent.CyclicBarrier.dowait (Unknown Source) at JAVA.UTIL.CONCURRENT.CYCL Icbarrier.await (Unknown Source) at Com.cxh.test1.test$writer.run (Test.java:58) java.util.concurrent.BrokenBarrierException at java.util.concurrent.CyclicBarrier.dowait (Unknown Source) at Ja Va.util.concurrent.CyclicBarrier.await (Unknown Source) at Com.cxh.test1.test$writer.run (Test.java:58) java.util.concurrent.BrokenBarrierException at java.util.concurrent.CyclicBarrier.dowait (Unknown Source) at Ja Va.util.concurrent.CyclicBarrier.await (Unknown Source) at Com.cxh.test1.test$writer.run (Test.java:58) Thread-2 Thread write completed, continue processing other tasks ... java.util.concurrent.BrokenBarrierException threads-3 Write data complete, wait for other threads to write at java.util.concurrent.CyclicBarrier.dowait (Unknown Source) at Java.util.concurrent.CyclicB Arrier.await (Unknown Source) at Com.cxh.test1.test$writer.run (Test.java:58) Thread-3 thread write completed, continue processing other tasks ...
View Code
The above code deliberately lets the last thread start the delay in the for loop of the main method, because after the previous three threads have reached barrier, waiting for the specified time to discover that the fourth thread has not reached barrier, throws an exception and continues with the subsequent task.
In addition Cyclicbarrier can be reused, see the following example:
public class Test {public static void main (string[] args) {int N = 4; Cyclicbarrier Barrier = new Cyclicbarrier (N), for (int i=0;i<n;i++) {new Writer (barrier). Start (); try {thread.sleep (25000);} catch (Interruptedexception e) {e.printstacktrace ();} System.out.println ("cyclicbarrier reuse"); for (int i=0;i<n;i++) {new Writer (barrier). Start ();}} Static class writer extends thread{private Cyclicbarrier cyclicbarrier;public writer (cyclicbarrier Cyclicbarrier) { This.cyclicbarrier = Cyclicbarrier;} @Overridepublic void Run () {System.out.println ("thread" +thread.currentthread (). GetName () + "writing data ..."); try { Thread.Sleep (the); Use sleep to simulate the write data operation System.out.println ("Thread" +thread.currentthread (). GetName () + "write data, wait for other threads to finish writing"); Cyclicbarrier.await ();} catch (Interruptedexception e) {e.printstacktrace ();} catch (Brokenbarrierexception e) {e.printstacktrace ();} System.out.println (Thread.CurrentThread (). GetName () + "All threads have finished writing, continue processing other tasks ...");}}
Execution Result:
Thread thread-0 Writing data ... Threads Thread-1 Writing data ... Threads Thread-3 Writing data ... Threads Thread-2 Writing data ... Threads Thread-1 Write the data, wait for other threads to finish writing threads thread-3 Write the data, wait for other threads to finish writing threads thread-2 Write the data, wait for other threads to finish writing threads thread-0 Write data finished, wait for other threads to finish writing thread-0 Thread write completed, continue processing other tasks ... Thread-3 Thread write completed, continue processing other tasks ... Thread-1 Thread write completed, continue processing other tasks ... Thread-2 Thread write completed, continue processing other tasks ... Cyclicbarrier Reusing threads thread-4 Writing data ... Threads Thread-5 Writing data ... Threads Thread-6 Writing data ... Threads Thread-7 Writing data ... Threads Thread-7 Write the data, wait for other threads to finish writing threads thread-5 Write the data, wait for other threads to finish writing threads thread-6 Write the data, wait for other threads to finish writing threads thread-4 Write data finished, wait for other threads to finish writing thread-4 Thread write completed, continue processing other tasks ... Thread-5 Thread write completed, continue processing other tasks ... Thread-6 Thread write completed, continue processing other tasks ... Thread-7 thread write completed, continue processing other tasks ...
View Code
As can be seen from the execution results, after the first 4 threads have crossed the barrier state, they can be used for a new round of use. And Countdownlatch cannot be reused.
Three. Semaphore usage
Semaphore translates into a semaphore, Semaphore can control the number of simultaneous accesses, obtain a license through acquire (), and if no wait, release () releases a license.
The Semaphore class is located under the Java.util.concurrent package, which provides 2 constructors:
public Semaphore (int permits) { ///parameter permits represents the number of licenses, that is, how many threads can be allowed to access sync = new Nonfairsync (permits);} public Semaphore (int permits, Boolean fair) { //This is more than one parameter fair indicates whether it is fair, that is, the longer the wait time, the first to obtain the license sync = (FAIR)? New Fairsync (permits): New Nonfairsync (permits);}
Here are some of the more important methods in the semaphore class, the first is the acquire (), Release () method:
public void Acquire () throws Interruptedexception { } //Get a license public void acquire (int permits) throws interruptedexception {} //Get permits License public void release () {} //release a license public void release (int permits) {}
//release of permits license
Acquire () is used to obtain a license that, if obtained without permission, waits until the license is granted.
Release () is used for releasing the license. Note that permission must be granted before releasing the license.
These 4 methods will be blocked, if you want to get the results immediately, you can use the following methods:
public Boolean Tryacquire () {}; Attempt to obtain a license that, if successful, returns true immediately, and returns Falsepublic Boolean tryacquire (long timeout, timeunit unit) immediately if the acquisition fails throws interruptedexception {}; An attempt is made to obtain a license that returns true immediately if it succeeds within the specified time, or returns falsepublic boolean tryacquire (int permits) {} immediately; Attempt to obtain permits license, if successful, returns true immediately, returns Falsepublic boolean tryacquire (int permits, long timeout, timeunit unit) if the acquisition fails Throws Interruptedexception {}; An attempt was made to obtain a permits license that returns true immediately if it succeeds within the specified time, or returns false immediately.
You can also get the number of licenses available through the Availablepermits () method.
Let's take a look at the specific use of semaphore in the following example:
If there are 5 machines in a factory, but there are 8 workers, one machine can only be used by one worker, and the other workers can continue to use it only after the use is finished. Then we can make it through semaphore:
public class Test {public static void main (string[] args) {int N = 8; Number of workers semaphore semaphore = new semaphore (5); Number of machines for (int i=0;i<n;i++) New Worker (I,semaphore). Start (); Static class Worker extends Thread{private int num;private Semaphore semaphore;public Worker (int num,semaphore Semaphore) {This.num = Num;this.semaphore = semaphore;} @Overridepublic void Run () {try {semaphore.acquire (); System.out.println ("Worker" +this.num+ "occupies a machine in production ..."); Thread.Sleep (2000); System.out.println ("Worker" +this.num+ "releasing the Machine"); Semaphore.release ();} catch (Interruptedexception e) {e.printstacktrace ();}}}}
Execution Result:
Worker 0 occupies a machine in production ... Worker 1 occupies a machine in production ... Worker 2 occupies a machine in production ... Worker 4 occupies a machine in production ... Worker 5 occupies a machine in production ... The worker 0 released the machine Worker 2 released the machine worker 3 occupied a machine in production ... Worker 7 occupies a machine in production ... The worker 4 released the machine worker 5 released the machine worker 1 released the machine worker 6 occupied a machine in production ... Worker 3 releases the machine worker 7 releases the machine worker 6 releases the machine
View Code
Here is a summary of the three auxiliary classes mentioned above:
1) Countdownlatch and Cyclicbarrier are capable of waiting between threads, except that they focus differently:
Countdownlatch is typically used when a thread a waits for several other threads to finish executing a task before it executes;
And Cyclicbarrier is generally used for a group of threads to wait for each other to a certain state, then this group of threads execute concurrently;
In addition, Countdownlatch cannot be reused, and cyclicbarrier can be reused.
2) Semaphore is actually a bit like a lock, which is typically used to control access to a group of resources.
Resources:
The idea of Java programming
Http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html
Http://leaver.me/archives/3220.html
Http://developer.51cto.com/art/201403/432095.htm
http://blog.csdn.net/yanhandle/article/details/9016329
http://blog.csdn.net/cutesource/article/details/5780740
Http://www.cnblogs.com/whgw/archive/2011/09/29/2195555.html
Java Concurrency Programming: Countdownlatch, Cyclicbarrier, and semaphore