Original: Curly brace MC(wechat official account: Huakuohao-MC) Focus on JAVA basic programming and big data, focus on experience sharing and personal growth.
This is the fifth article in the concurrent programming series. The JDK provides three concurrency classes, locking, fencing, and semaphores.
Closure – CountDownLatch
A latching is similar to a gate, outside which all threads wait, and when the gate opens, all threads work together.
CountDownLatch provides a constructor that passes in an integer as an argument to represent the initial counter. Every time the countDown() method is called, the counter decreases by one, and when it reaches 0, the gate is open. Think of the CountDownLatch as a countdown counter for racing cars. When the counter is zero, all cars accelerate out.
Let’s demonstrate the use of CountDownLatch by developing a simple stress test widget.
When testing the processing capability of a system, the test tool is often required to simulate the situation of multiple clients initiating requests to the server at the same time, so as to judge the anti-pressure capability of the system. The following code implements this feature with CountDownLatch and counts the completion time of the last request to determine the maximum TPS of the system.
public class Task implements Runnable {
// Start counter
private final CountDownLatch startGate;
// End the counter
private final CountDownLatch endGate;
public Task(CountDownLatch startGate, CountDownLatch endGate){
this.startGate = startGate;
this.endGate = endGate;
}
@Override
public void run(a) {
try {
// The created thread waits here
startGate.await();
System.out.println(Thread.currentThread().getName() + "Commence execution" + System.currentTimeMillis());
// Simulate real task execution
Thread.sleep(new Random().nextInt(10) *100);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// When the thread is finished, the end counter is reduced by oneendGate.countDown(); }}}Copy the code
The test program
/** * Wait for each thread to be created, and then start executing together. * At the end of each thread, the endGate is automatically reduced by one, so that the main thread will wait for all threads to complete the operation before counting the time. * /
public class CountDownLatchDemo {
private static CountDownLatch startGate = new CountDownLatch(1);
private static CountDownLatch endGate = new CountDownLatch(4);
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 4; i++){
Thread thread = new Thread(new Task(startGate,endGate));
thread.start();
}
long startTime = System.nanoTime();
System.out.println("All threads start executing");
startGate.countDown();
endGate.await();
long endTime = System.nanoTime();
System.out.println("Total cost of executing tasks in parallel"+ (endTime - startTime)); }}Copy the code
The fence – CyclicBarrier
Fences and lockouts are similar in that they both wait until a condition occurs. Fences are typically used for threads to wait on each other, while latches are more likely to wait on an event, and cyclicbarriers can be reused through the reset() method, whereas CountDownLatch is not.
For example Front page display content is often the background over here from multiple sources of data, this time we can launch multiple threads, each thread a data calculation, but each data calculation is different, the return time is different also, but we have to wait for all the data returned, returned to the front do show together. CyclicBarrier can be used to help.
CyclicBarrier code demo
public class CounterTask implements Runnable {
private CyclicBarrier cyclicBarrier;
public CounterTask(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run(a) {
System.out.println(Thread.currentThread().getName() + "start");
try {
// Simulate calculation time
Thread.sleep(new Random().nextInt(10) *100);
System.out.println(Thread.currentThread().getName()+ "complete!");
// Wait for another thread
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch(BrokenBarrierException e) { e.printStackTrace(); }}}Copy the code
The test program
/** * Can only be displayed on the front desk when multiple groups of data have been calculated. * /
public class CyclicBarrierDemo {
public static void main(String[] args){
CyclicBarrier cyclicBarrier = new CyclicBarrier(5.new Runnable() {
@Override
public void run(a) {
System.out.println("Mission accomplished, ready to go forward."); }});for (int i = 0; i < 5; i++){
Thread thread = new Thread(newCounterTask(cyclicBarrier)); thread.start(); }}}Copy the code
As we saw in the code above, in addition to the computation tasks defined, we can also supply the fence with an anonymous Runnable constructor that represents the tasks to be performed when the counter is 0. The above code has been demonstrated, not to do too much explanation.
Semaphore – Semaphore
Previously described locks, whether synchronized or synchronized, allow only one thread to access a shared resource, whereas semaphores allow N threads to access a shared resource simultaneously.
You can think of semaphores as sheets of licenses that allow the thread to manipulate shared resources, acquire them through the acquire method and return them through the Release method. If no license is available, the acquire method blocks.
Semaphores are generally used to implement resource pools, and when no resources are available from the pool, the thread applying for the resource will block until the pool has available resources.
For example
The use of semaphores to achieve a limited number of client login function. LoginTask
public class LoginTask implements Runnable {
private Semaphore semaphore;
private int userId;
public LoginTask(int userId, Semaphore semaphore) {
this.userId = userId;
this.semaphore = semaphore;
}
@Override
public void run(a) {
try {
// Get permission
semaphore.acquire();
System.out.println("The first" + userId + "User Login");
// Simulate login duration
Thread.sleep(new Random().nextInt(10) *2000);
System.out.println("The first" + userId + "Subscriber Launch");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// Release resources after exitsemaphore.release(); }}}Copy the code
Simulated user login
public class SemaphoreLoginDemo {
public static void main(String[] args){
// Create five license resources
Semaphore semaphore = new Semaphore(5);
for (int i = 0; i < 10; i++){
Thread thread = new Thread(newLoginTask(i,semaphore)); thread.start(); }}}Copy the code
In the code above, you can see that initially five users log in, and then only when the user logs out, will another user log in.
The end of the
This article introduces three utility classes that are commonly used in concurrent programming and illustrates them with code examples. The next article will cover the Executor framework and thread pooling technology provided by the JDK.
Recommended reading
1. Concurrent programming in Java (I) — tasks and threads
Java8 Stream is really delicious, you never know if you haven’t experienced it
3. Do you know how to use Awk
4. Teach you how to build a set of ELK log search operation and maintenance platform
, END,
Curly braces MC
Java· Big Data · Personal growth
Wechat id: Huakuohao-MC