[JAVA concurrency] synchronization tool and java concurrency Tool
Synchronization tools include locking (such as CountDownLatch), barrier (such as CyclicBarrier), semaphores (such as Semaphore), and blocking queues (such as LinkedBlockingQueue;
The synchronization tool class can be used to coordinate the thread control flow;
The synchronization tool class encapsulates some States, which determine whether the thread continues or waits. In addition, the synchronization tool class also provides methods to modify the State;
The following describes the synchronization tool categories;
Locking
A thread can wait for a group of events (not necessarily end with the thread) to continue execution;
Take CountDownLatch as an example. It contains a counter, Which is initialized as an integer (number of events) at the beginning. After an event occurs, the countDown method is called to reduce the counter by 1, await is used to continue executing the current thread after the counter is 0;
For example, the main thread continues to execute the main thread after the event of other sub-threads occurs:
Package concurrency; import java. text. simpleDateFormat; import java. util. date; import java. util. concurrent. countDownLatch; import java. util. concurrent. executorService; import java. util. concurrent. executors; import java. util. concurrent. timeUnit; class TaskTest implements Runnable {private CountDownLatch latch; private int sleepTime;/*****/public TaskTest (int sleepTime, CountDownLatch latch) {this. slee PTime = sleepTime; this. latch = latch;}/*** @ see java. lang. runnable # run () */@ Override public void run () {try {CountDownLatchTest. print ("is running. "); TimeUnit. MILLISECONDS. sleep (sleepTime); CountDownLatchTest. print (" finished. "); // The counter minus latch. countDown ();} catch (InterruptedException e) {e. printStackTrace () ;}} public class CountDownLatchTest {public static void main (String [] args) {int count = 10; final CountDownLatch latch = new CountDownLatch (count ); executorService es = Executors. newFixedThreadPool (count); for (int I = 0; I <count; I ++) {es.exe cute (new TaskTest (I + 1) * 1000, latch ));} try {CountDownLatch Test. print ("waiting... "); // The main thread waits for other events to occur latch. await (); // other events have occurred. Continue to execute the main thread CountDownLatchTest. print ("continue... ");} Catch (InterruptedException e) {e. printStackTrace ();} finally {es. shutdown () ;}} public static void print (String str) {SimpleDateFormat dfdate = new SimpleDateFormat ("HH: mm: ss"); System. out. println ("[" + dfdate. format (new Date () + "]" + Thread. currentThread (). getName () + str );}}
The result is printed as follows:
[09:41:43]pool-1-thread-1 is running。[09:41:43]pool-1-thread-6 is running。[09:41:43]main waiting...[09:41:43]pool-1-thread-10 is running。[09:41:43]pool-1-thread-4 is running。[09:41:43]pool-1-thread-5 is running。[09:41:43]pool-1-thread-2 is running。[09:41:43]pool-1-thread-3 is running。[09:41:43]pool-1-thread-7 is running。[09:41:43]pool-1-thread-8 is running。[09:41:43]pool-1-thread-9 is running。[09:41:44]pool-1-thread-1 finished。[09:41:45]pool-1-thread-2 finished。[09:41:46]pool-1-thread-3 finished。[09:41:47]pool-1-thread-4 finished。[09:41:48]pool-1-thread-5 finished。[09:41:49]pool-1-thread-6 finished。[09:41:50]pool-1-thread-7 finished。[09:41:51]pool-1-thread-8 finished。[09:41:52]pool-1-thread-9 finished。[09:41:53]pool-1-thread-10 finished。[09:41:53]main continue。。。
In addition, FutureTask can also be used as a lock. The get method will wait for the result to be returned after the task is completed; otherwise, it will be blocked until the task is completed;
Semaphores
Control the number of operations that can be performed at the same time. It is often used to implement resource pools, such as database connection pools and thread pools...
Taking Semaphore as an example, it maintains a group of resources internally. You can specify the number by using the constructor. Other threads can obtain resources through the acquire method during execution. If yes, continue execution (release resources after use). If there is no resource, it will be blocked until other threads call the release method to release the resource;
For example, as shown in the following code, ten threads compete for three resources. Three threads can run directly at the beginning, and the remaining seven threads can only be blocked until other threads use resources;
Package concurrency; import java. text. simpleDateFormat; import java. util. date; import java. util. concurrent. executorService; import java. util. concurrent. executors; import java. util. concurrent. semaphore; import java. util. concurrent. timeUnit; public class SemaphoreTest {public static void print (String str) {SimpleDateFormat dfdate = new SimpleDateFormat ("HH: mm: ss"); System. out. println ("[" + dfdate. format (new Date () + "]" + Thread. currentThread (). getName () + str);} public static void main (String [] args) {// Number of threads int threadCount = 10; // number of resources Semaphore semaphore = new Semaphore (3); ExecutorService es = Executors. newFixedThreadPool (threadCount); // start several threads for (int I = 0; I <threadCount; I ++) es.exe cute (new ConsumeResourceTask (I + 1) * 1000, semaphore) ;}} class implements Runnable {private Semaphore semaphore; private int sleepTime;/*****/public ConsumeResourceTask (int sleepTime, Semaphore semaphore) {this. sleepTime = sleepTime; this. semaphore = semaphore;} public void run () {try {// obtain the resource semaphore. acquire (); SemaphoreTest. print ("occupies a resource... "); TimeUnit. MILLISECONDS. sleep (sleepTime); SemaphoreTest. print ("End of resource use, release resource"); // release the resource semaphore. release ();} catch (InterruptedException e) {e. printStackTrace ();}}}
[10:30:11] pool-1-thread-1 occupies a resource... [10:30:11] pool-1-thread-2 occupies a resource... [10:30:11] pool-1-thread-3 occupies a resource... [10:30:12] pool-1-thread-1 resources are used up. Releasing resources [10:30:12] pool-1-thread-4 occupies a resource... [10:30:13] pool-1-thread-2 resources are used up. Releasing resources [10:30:13] pool-1-thread-5 occupies a resource... [10:30:14] pool-1-thread-3 resources are used up. Releasing resources [10:30:14] pool-1-thread-8 occupies a resource... [10:30:16] pool-1-thread-4 resources are used up. Releasing resources [10:30:16] pool-1-thread-6 occupies a resource... [10:30:18] pool-1-thread-5 resources are used up. Releasing resources [10:30:18] pool-1-thread-9 occupies a resource... [10:30:22] pool-1-thread-8 resources are used up. Releasing resources [10:30:22] pool-1-thread-7 occupies a resource... [10:30:22] pool-1-thread-6 resources are used up. Releasing resources [10:30:22] pool-1-thread-10 occupies a resource... [10:30:27] pool-1-thread-9 resources are used up, and resources are released [10:30:29] pool-1-thread-7 resources are used up, release resources [10:30:32] pool-1-thread-10 resource usage is complete, release resources
Barrier
The fence is used to wait for other threads and blocks the current thread;
All threads can continue execution only after they reach the barrier;
For example:
Package concurrency; import java. text. simpleDateFormat; import java. util. date; import java. util. concurrent. brokenBarrierException; import java. util. concurrent. cyclicBarrier; import java. util. concurrent. executorService; import java. util. concurrent. executors; import java. util. concurrent. timeUnit; class extends icbarriertasktest implements Runnable {private extends icbarrier; private int timeout; public extends icbarriertasktest (CyclicBarrier extends icbarrier, int timeout) {this. required icbarrier = required icbarrier; this. timeout = timeout ;}@ Override public void run () {testpolicicbarrier. print ("running... "); try {TimeUnit. MILLISECONDS. sleep (timeout); TestCyclicBarrier. print ("arriving at the barrier, waiting for other threads to arrive"); cyclicBarrier. await ();} catch (InterruptedException e) {e. printStackTrace ();} catch (BrokenBarrierException e) {e. printStackTrace ();} TestCyclicBarrier. print ("All threads reach the barrier and continue to execute their respective thread tasks... ") ;}} public class testpolicicbarrier {public static void print (String str) {SimpleDateFormat dfdate = new SimpleDateFormat (" HH: mm: ss "); System. out. println ("[" + dfdate. format (new Date () + "]" + Thread. currentThread (). getName () + str);} public static void main (String [] args) {int count = 5; ExecutorService es = Executors. newFixedThreadPool (count); CyclicBarrier barrier = new CyclicBarrier (count, new Runnable () {@ Override public void run () {TestCyclicBarrier. print ("All threads reach the barrier, and some processing can be done here... ") ;}}); for (int I = 0; I <count; I ++) es.exe cute (new icicbarriertasktest (barrier, (I + 1) * 1000 ));}}
[11:07:00] pool-1-thread-2 is running... [11:07:00] pool-1-thread-1 is running... [11:07:00] pool-1-thread-5 is running... [11:07:00] pool-1-thread-3 is running... [11:07:00] pool-1-thread-4 is running... [11:07:01] pool-1-thread-1 arrives at the barrier and waits for other threads to arrive at [11:07:02] pool-1-thread-2 to arrive at the barrier, wait for other threads to reach the barrier at [11:07:03] pool-1-thread-3, and wait for other threads to reach the barrier at [11:07:04] pool-1-thread-4, wait for other threads to reach the barrier at [11:07:05] pool-1-thread-5, and wait for other threads to reach the barrier at [11:07:05] pool-1-thread-5, you can do some processing here... [11:07:05] all the threads in pool-1-thread-1 reach the barrier and continue to execute their respective thread tasks... [11:07:05] all the threads in pool-1-thread-2 reach the barrier and continue to execute their respective thread tasks... [11:07:05] all the threads in pool-1-thread-5 reach the barrier and continue to execute their respective thread tasks... [11:07:05] all the threads in pool-1-thread-3 reach the barrier and continue to execute their respective thread tasks... [11:07:05] all the threads in pool-1-thread-4 reach the barrier and continue to execute their respective thread tasks...
Blocking queue
The blocking queue provides a blocking queue and a pair of operations. If the queue is full, the queuing operation will be blocked until there is space available. If the queue is empty, the queuing operation will be blocked until there are available elements;
The queue can be a bounded or unbounded queue, and the unbounded queue is not full. Therefore, the queuing operation will not be blocked;
The following uses the blocking queue blockingqueue as an example of a producer-consumer. The producer produces one product every one second, and then six consumers consume the product. It can be found that every one second, only one consumer can get the product consumption, and other threads can only wait...
The following code:
Package concurrency; import java. text. simpleDateFormat; import java. util. date; import java. util. concurrent. blockingQueue; import java. util. concurrent. linkedBlockingQueue; import java. util. concurrent. timeUnit; // Producer public class Producer implements Runnable {private final BlockingQueue <String> fileQueue; public Producer (BlockingQueue <String> queue) {this. fileQueue = queue;} public void run () {try {while (true) {TimeUnit. MILLISECONDS. sleep (1000); String produce = this. produce (); System. out. println (Thread. currentThread () + "Production:" + produce); fileQueue. put (produce) ;}} catch (InterruptedException e) {Thread. currentThread (). interrupt () ;}} public String produce () {SimpleDateFormat dfdate = new SimpleDateFormat ("HH: mm: ss"); return dfdate. format (new Date ();} public static void main (String [] args) {BlockingQueue <String> queue = new LinkedBlockingQueue <String> (10 ); for (int I = 0; I <1; I ++) {new Thread (new Producer (queue )). start () ;}for (int I = 0; I <6; I ++) {new Thread (new Consumer (queue )). start () ;}}// Consumer class Consumer implements Runnable {private final BlockingQueue <String> queue; public Consumer (BlockingQueue <String> queue) {this. queue = queue;} public void run () {try {while (true) {TimeUnit. MILLISECONDS. sleep (1, 1000); System. out. println (Thread. currentThread () + "prepare consumption"); System. out. println (Thread. currentThread () + "starting:" + queue. take (); System. out. println (Thread. currentThread () + "end consumption") ;}} catch (InterruptedException e) {Thread. currentThread (). interrupt ();}}}
Thread [Thread-1, 5, main] prepare consumption Thread [Thread-3, 5, main] prepare consumption Thread [Thread-4, 5, main] prepare consumption Thread [Thread-2, 5, main] prepare consumption Thread [Thread-6, 5, main] prepare consumption Thread [Thread-5, 5, main] prepare consumption Thread [Thread-0, 5, main] production: 11: 36: 36 Thread [Thread-1, 5, main] starting: 11: 36: 36 Thread [Thread-1, 5, main] end consumption Thread [Thread-1, 5, main] prepare consumption Thread [Thread-0, 5, main] production: 11: 36: 37 Thread [Thread-4, 5, main] starting: 11: 36: 37 Thread [Thread-4, 5, main] end Thread [Thread-4, 5, main] prepare consumption Thread [Thread-0, 5, main] production: 11: 36: 38 Thread [Thread-3, 5, main] starting: 11: 36: 38 Thread [Thread-3, 5, main] end consumption
...
References: java concurrent programming practices