Analysis of cyclicbarrier source code of Java Concurrent series

In real life, we often encounter such a situation. We need to wait for all the people before starting an activity. For example, when eating, you have to wait for the whole family to be seated before moving chopsticks, when traveling, you have to wait for all the people to arrive before starting, and when competing, you have to wait for the athletes to play before starting. The JUC package provides us with a synchronization tool class, which can well simulate such scenarios. It is the cyclicbarrier class. Using the cyclicbarrier class, a group of threads can wait for each other. When all threads reach a barrier point, they can carry out subsequent operations. The following figure illustrates this process.

There is a counter inside the cyclicbarrier class. When each thread reaches the barrier point, it will call the await method to block itself. At this time, the counter will decrease by 1. When the counter decreases to 0, all threads blocked by calling the await method will be awakened. This is the principle of a group of threads waiting for each other. Let's take a look at the member variables of cyclicbarrier.

All member variables of the cyclicbarrier are posted above. It can be seen that the cyclicbarrier blocks threads through the condition queue trip, and maintains two int variables parties and count. Parties represents the number of threads intercepted each time. This value is assigned during construction. Count is an internal counter. Its initial value is the same as that of parties. In the future, it will be reduced by 1 with each call of await method until it is reduced to 0, and all threads will wake up. Cyclicbarrier has a static internal class generation. The object of this class represents the current generation of the fence, just like the local game represented when playing the game. It can be used to realize circular waiting. Barriercommand indicates the task executed before the generation change. When the count is reduced to 0, it indicates that the game in this game is over and needs to go to the next game. Before going to the next game, you will wake up all blocked threads. Before waking up all threads, you can perform your own tasks by specifying barriercommand. Next, let's look at its constructor.

Cyclicbarrier has two constructors, of which constructor 1 is its core constructor. Here you can specify the number of participants in the game (the number of threads to be intercepted) and the tasks to be executed at the end of the game. You can also see that the initial value of the counter count is set to parties. The main function of the cyclicbarrier class is to block the thread that reaches the barrier point first and wait for the subsequent thread. It provides two waiting methods, timed waiting and untimed waiting.

You can see that whether it is a timed wait or an untimed wait, they all call the dowait method, but the parameters passed in are different. Let's take a look at what the dowait method does.

The comments in the code posted above are quite detailed. We only pick some important ones. It can be seen that in the dowait method, count is decremented by 1 every time. After the decrement, judge immediately to see if it is equal to 0. If it is equal to 0, it will first execute the previously specified task, and then call the nextgeneration method to transfer the fence to the next generation. In this method, all threads will wake up and reset the counter value to parties, Finally, the fence generation will be reset. After executing the nextgeneration method, it means that the game enters the next game. If the counter is not equal to 0 at this time, it will enter the for loop and decide whether to call trip according to the parameters Awaitnanos (nanos) or trip Await () method, which corresponds to timed and untimed waiting. If the current thread is interrupted during the waiting process, the breakbarrier method will be executed. This method is called breaking the fence, which means that the game is cut off halfway, set the broken state of generation to true and wake up all threads. At the same time, it also shows that one thread is interrupted during the waiting process, the whole game will end, and all previously blocked threads will be awakened. After waking up, the thread will execute the following three judgments to see if it is awakened by calling the breakbarrier method. If so, an exception will be thrown; Check whether it is awakened due to normal generation operation. If so, return the value of the counter; See if you are awakened due to timeout. If so, call breakbarrier to break the fence and throw an exception. It should also be noted here that if one thread exits due to waiting timeout, the whole game will end and other threads will be awakened. The specific codes of the nextgeneration method and the breakbarrier method are posted below.

Above, we have basically explained the principle of cyclicbarrier through the source code. Next, we will deeply grasp its use through an example of horse racing.

The horse racing program mainly prints the current track of each horse race on the console, so as to achieve the effect of dynamic display. There are multiple rounds in the whole race. Each race will take several steps at random and then call the await method to wait. When all races are finished, they will perform the task and print the current track of all races onto the console. In this way, the track of each horse race keeps growing at the end of each round. When the track of a horse race first increases to the specified value, the whole race will end and the horse race will become the winner of the whole race! The running results of the program are as follows:

At this point, we will inevitably compare cyclicbarrier with countdownlatch. These two classes can implement a group of threads to wait before reaching a certain condition. There is a counter inside them. When the value of the counter is continuously reduced to 0, all blocked threads will be awakened. The difference is that the cyclicbarrier counter is controlled by itself, while the countdownlatch counter is controlled by the user. In the cyclicbarrier, the thread calling the await method will not only block itself, but also reduce the counter by 1. In the countdownlatch, the thread calling the await method only blocks itself without reducing the counter value. In addition, countdownlatch can only intercept one round, while cyclicbarrier can realize circular interception. Generally speaking, the countdownlatch function can be realized with cyclicbarrier, but not on the contrary. For example, the above racing program can only be realized with cyclicbarrier. In short, the similarities and differences between the two classes are roughly the same. Readers need to decide when to use cyclicbarrier and countdownlatch.

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>