Hello, I’m Xiao Dai. A man who wants to be a big talk about architecture! If you also want to be the person I want to be, or point a concern to be a companion, let small dish no longer lonely!

This paper mainly introduces the necessary concurrent tools for moving bricks

Come to all come, a point to see how ~!

WeChat public account has been opened, XiaoDai Liang remember, did not pay attention to the students remember to pay attention!

As a brick-lifting engineer lying flat, the slow moving of bricks may have left you behind during the inwinding period. Bricks are a shared resource. Nowadays, every brick remover wants to pursue quality while maintaining an efficient moving rate. Will there be concurrency in the situation of competition? The bricks you have moved are counted on someone else’s KPI. The original intention is to lie flat, but it never occurred to you that lying flat will also be so unfair! The salted fish used to be fried on one side, but now they have to turn the other side over and fry it again.

Finally, lying flat brickwork decided not to lie flat, he pinched his fist, teeth bite “jag” sound, his face as yellow as wax, lips bite white, the original few hair a shiver a shiver, the whole body in the shivering, mercily decided: I must solve the concurrent problem! Let the normal operation of moving brick industry ~!

What? Normal operation, then have to solve the concurrency problem!

OK, OK, the atmosphere is right, this time the small dish slowly comes on stage, then enters the topic, solves the concurrency problem what is the concurrency tool class that you commonly use?

Several very useful concurrency utility classes are already available in the JDK’s concurrent package.

  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • Exchanger

These may be familiar to some partners, may be a little bit of raw, familiar to see but can not use and see the raw points are no different. Then we will be able to let you in the usual development of the use of ease through a simple elaboration!

A, CountDownLatch

This is one of the most common concurrent tools in development. It is an inverse counter. The multithreading control utility class is a very useful multithreading control utility class, this utility class is used to control the thread wait, can make a thread wait until the counter ends before starting to execute!

We don’t have to delve into the source code at first, we can use it first and then use it well. So let’s look at a very simple example

Not One Less

Miss Wang is a strict teacher. She is a little wayward in class. She has to wait until all the students (10) are present before the class starts, which means that if one student is not present, the class will not begin.

We have to follow a requirement that can not be less, that is, when the number of students < the total number of students can not perform the action of the class. So how should we deal with this problem at this time?

We call the roll before class and add an IF judgment. When the number of students is not satisfied, they will not enter the action of class. This may be a conventional thinking, most students will operate in this way. Then the problem comes, some students may just miss the judgment of roll call because they are late, and they will not make the judgment after the execution of IF, so missing is missing. Although the following number of students have arrived, they can not start the class in the end!

If you think about it a little bit better, if the problem is that if only evaluates once, can we keep judging, then you can use either while or for to keep iterating. If the solution is correct, let’s introduce the use of CountDownLatch

The code is not long, but I don’t know if the results are as we hoped:

We can see that when the 10 students all arrive, Miss Wang starts the class, but what if we are one student who doesn’t arrive?

When the number of students does not meet the expectation, the class will not be normal. At present, it has met our needs. Then let’s simulate the scene of students being late

Is still the student number for 10 students, although late but arrived, the class or can be carried on normally!

CountDownLatch is a great tool for solving this problem in a very simple way! So how did he solve it?

CountDownLatch is implemented with a counter, which is first set to an initial value. Each time a task completes, the value of the counter decrements by 1, and when the counter reaches 0, it indicates that all tasks have been completed, and then threads waiting on the lock can resume executing the task.

The first thing we can look at is the constructor for CountDownLatch

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

This method initializes a count and initializes a Sync, which is the underlying function of CountDownLatch. Let’s see what Sync is.

You can see that inside Sync there is a security variable, STATE, whose value is the value of the counter. There are two important methods: tryAcquireShared(int reshares) and tryreleaseShared (int releases). So what’s the use of these two methods?

Let’s go back to the CountDownLatch class. We’ve already seen the constructor in action, and now we need to recognize two important methods: countDown() and await(). In our view, the countDown() method is to subtract 1 from the count, and the await() method is to block to see if the count is 0. So let’s go to the corresponding method and see how does that work

public void countDown() {
    sync.releaseShared(1);
}
---
public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

These two methods call two methods in AQS :(I will post the source code comment directly here, look carefully!)

countDown()

await()

This is the CountDownLatch implementation, so let’s think about how this utility class could be used in a real-time system:

  1. Achieve maximum parallelism

When we want to start multiple threads at the same time, we achieve maximum parallelism. For example, if we want to test a singleton class, if we create a countDownLatch with an initial value of 1 and make all threads wait on the lock, we can easily complete the test by calling countDownLatch () once to get all waiting threads to resume execution at the same time

  1. Wait for n threads to complete their tasks before starting execution

Before our application executes, make sure that some pre-action needs to be performed

  1. Deadlock detection

We can use n threads to access the shared resource, the number of threads varies during each test phase, and this can attempt to generate a deadlock

Second, the CyclicBarrier

CyclicBarrier is another multithreaded concurrency control tool. Cyclic means Cyclic, which means this counter can be used over and over again. It’s a little more powerful than CountDownLatch, and all it does is let a group of threads get blocked when they reach a barrier (also known as a synchronization point) until the last thread reaches the barrier, and the barrier doesn’t open until the last thread reaches the barrier. All threads blocked by the barrier will continue to work.

That is to say, cyclicBarrier is an addition timer. Let’s use the above example “Not One Less” to show how to use it

I won’t show the absences and lateness demonstrations here, just like I did with CountDownLatch

Here we are again concerned with the two methods, the constructor and the await().

We still go into the CyclicBarrier class to look at the constructor

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

We are looking at the await() method instead of countDownLatch. This constructor only records the barrier points

public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen
    }
}

Going back to the dowait() method, we can see that the implementation is not complicated. Since the code is a bit long, we cut out the highlights

Unlike CountDownLatch, barrier point variables are not volatile, so they need not be locked to make them thread-safe!

The above is the whole implementation process of CyclicBarrier, specific we don’t pull the details ~!

CyclicBarrier and CountDownLatch are somewhat similar, but let’s be clear about the difference:

  1. CountDownLatch: A thread (or threads) that waits for N other threads to finish doing something before it executes
  2. CyclicBarrier: N threads wait for each other, and all the threads must wait until any one of them completes

Important point: CountDownLatch is not reusable, CyclicBarrier is not reusable

Third, Semaphore

Semaphore (Semaphore) is a more powerful control method for multithreading. In a broad sense, a semaphore is an extension of a lock. While synchronized and ReentrantLock allow only one thread to access one resource at a time, a semaphore can specify multiple threads to access a shared resource at the same time.

Let’s look at a very simple example

2. “Grab a Parking Space”

Originally, there were 5 parking Spaces on the ground in a community, which could well meet the parking needs of the owners. However, in recent years, the number of vehicles has increased rapidly, almost every family has one car, and the demand for parking Spaces naturally exceeds the supply. It can only follow the principle of first come, first served!

Then let’s look at the execution result:

It can be seen that the five parking Spaces are shared resources. Only the owner who arrives first can grab the parking space. When the owner who has grabbed the parking space leaves, the subsequent owners can enter and get the parking space!

We extract the concern constructor, acquire(), release()

A constructor

public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}

public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

Yes, Semaphore has two constructors, the difference being whether it uses fair locks or not. And then we’ll move on to aquire(), release()

public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

public void release() {
    sync.releaseShared(1);
}

excuse me~? For those of you who have been watching this, this calls the same method as countDownLatch. Yes, both of these concurrency utility classes have the underlying thread methods that call AQS. If you don’t know the effect of these two methods, you can look up, no more details here!

According to this tool class combined with the above example, we can use it in the flow control! Especially public resources limited application scenarios, such as a database connection, if there is a demand to read tens of thousands of file data, because is IO intensive tasks, we can start the dozens of thread to read concurrently, but we have to after a hard disk — – > > memory database, and only if the database connection number 10, We have to control that only 10 threads can access the database connection at the same time to save the data, so we can use Semaphore to do the flow control ~!

Fourth, the Exchanger

I don’t know how many people are thinking what is this? . To be honest, this tool class is really not high visibility, less used. This is a tool class used for collaboration between threads. It can be used for data exchange between threads. It provides a synchronization point where two threads can exchange data with each other. The two threads use this method to exchange data, and if the first one tries the exchange(), it waits for the second one to try the same, so when both reach the synchronization point, the two threads can exchange data. Pass the data produced by this thread to the other party.

And the thing to notice here is that there is no triangle between these two threads

Without exchange(), the numeric thread should print numbers and the alphabetic thread should print letters, but after exchange(), the result is reversed:

Note: If one of the two threads does not execute the exchange() method, it will wait

To avoid this, we can add a timeout to exchange()!

So what are the applications of this utility class? Let’s think the production cost of creating an object in one thread’s execution task is high and another thread needs to consume the object, then we can use this to help us transfer the class object. You can even implement a producer-consumer model!

The above is the use and application scenarios of several concurrent tool classes. Of course, the application scenarios mentioned above are only a small part. Of course, more of them need to continue to be explored in the development to make good use of them

See finally, move the brick engineer nipped out his hand in the cigarette end, smoke filled the air came a durable words: his mother, did not expect this year to move a brick is not easy

Don’t talk, don’t be lazy, and dishes together to do a blowing cattle X architecture program ape bar ~ point a concern to do a companion, let dishes no longer lonely. See you later!

Today you work harder, tomorrow you will be able to say less words for people!


I am small dish, a strong man with you.
💋


WeChat official account has been opened.
Good dishes to rememberRemember to pay attention to those who did not pay attention to oh!