Cyclicbarrier is a tool class under the Java.util.concurrent package that literally means a reusable (Cyclic) barrier (Barrier) that can be blocked when a set of threads reaches a barrier (also called a sync point), until the last thread reaches the barrier. All threads that are blocked by the barrier will continue to execute.
This article describes the following points in the Cyclicbarrier synchronization tool class
- Through the case analysis
- Two different kinds of constructor tests
- The difference between Cyclicbarrier and Countdownlatch
- Await method and source code analysis.
Demand
Following the previous CountDownLatch
simulation game loading, now that the user clicks the Start button, it is necessary to match five players including themselves to start the game, and match the player's success into the select role stage. When the 5-player character is selected, the game starts to enter. Enter the game need to load the relevant data, until all players are loaded after the official start of the game.
Solution Solutions
From the requirements to know, want to start the game need to go through three stages, respectively is
- Match players
- Select role
- Loading data
In these three phases, you need to wait for each other to complete before you can continue into the next phase.
This can be used CyclicBarrier
as a node for each stage, waiting for other players to arrive at the next stage.
Defining classes that inherit runnable
Here the name is called StartGame
, contains two attributes
private String player;private CyclicBarrier barrier;
Initialize two properties by constructor function
public StartGame(String player, CyclicBarrier barrier) { this.player = player; this.barrier = barrier;}
The Run method is as follows
public void run() { try { System.out.println(this.getPlayer()+" 开始匹配玩家..."); findOtherPlayer(); barrier.await(); System.out.println(this.getPlayer()+" 进行选择角色..."); choiceRole(); System.out.println(this.getPlayer()+" 角色选择完毕等待其他玩家..."); barrier.await(); System.out.println(this.getPlayer()+" 开始游戏,进行游戏加载..."); loading(); System.out.println(this.getPlayer()+" 游戏加载完毕等待其他玩家加载完成..."); barrier.await(); start(); } catch (Exception e){ e.printStackTrace(); }}
Other methods Findotherplayer (), choicerole () wait for use
Thread.sleep()
To simulate the time spent
Writing test Code
Cyclicbarrier has two constructors, as follows
public CyclicBarrier(int parties) {}public CyclicBarrier(int parties, Runnable barrierAction) {}
Let's take a look at the constructor of a parameter
Cyclicbarrier (int parties)
public static void main(String[] args) throws IOException { CyclicBarrier barrier = new CyclicBarrier(5); Thread player1 = new Thread(new StartGame("1",barrier)); Thread player2 = new Thread(new StartGame("2",barrier)); Thread player3 = new Thread(new StartGame("3",barrier)); Thread player4 = new Thread(new StartGame("4",barrier)); Thread player5 = new Thread(new StartGame("5",barrier)); player1.start(); player2.start(); player3.start(); player4.start(); player5.start(); System.in.read();}
The test results are as follows
Cyclicbarrier (int parties, Runnable barrieraction)
CyclicBarrier barrier = new CyclicBarrier(5);
Replaced by
CyclicBarrier barrier = new CyclicBarrier(5, () -> { try { System.out.println("阶段完成,等待2秒..."); Thread.sleep(2000); System.out.println("进入下个阶段..."); } catch (InterruptedException e) { e.printStackTrace(); }});
And look at the effect.
You can see that the Runnable object that is passed in when instantiating Cyclicbarrier is executed when a node is reached. And every time it arrives, it executes once.
The difference between Cyclicbarrier and Countdownlatch
Countdownlatch |
Cyclicbarrier |
The count is 0 o'clock and cannot be reset |
When the count reaches 0, the count is reset to the incoming value to start again |
Call the countdown () method Count minus one, call the await () method to block only, and have no effect on the count |
Call the await () method count minus one, and if the value after minus one is not equal to 0, the thread blocks |
No re-use |
can be reused |
Await method
public int await(){}public int await(long timeout, TimeUnit unit){}
The no-reference await method is not introduced here, mainly introduces the following await method.
A parameter await method passes two parameters, one is time, the other is the time unit
The following two exceptions occur when calling an await method with a parameter
java.util.concurrent.TimeoutExceptionjava.util.concurrent.BrokenBarrierException
TimeoutException exception refers to the call await
method after the wait time exceeds the incoming time, the CyclicBarrier
state will be changed to broken, the other calling method will await
throw brokenbarrierexception exception, when the CyclicBarrier
will become unavailable, the reset()
state of the method reset needs to be called CyclicBarrier
.
Why do you say that?
Source analysis A wave can be seen.
The await method, whether it is an argument or a non-argument, is called, and CyclicBarrier
dowait(boolean timed, long nanos)
The method code is too long, and the interception section is posted.
private int dowait(boolean timed, long nanos){ //加锁、try catch代码 final Generation g = generation; //判断栅栏的状态 if (g.broken) throw new BrokenBarrierException(); //...省略 int index = --count; //(index == 0) 时的代码,省略 for (;;) { try { if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) {} //判断栅栏的状态 if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; //判断是否是定时的,且已经超时了 if (timed && nanos <= 0L) { //打破栅栏的状态 breakBarrier(); throw new TimeoutException(); } } //解锁}
At the end of the code to determine whether the current wait has timed out, if it is called the breakBarrier()
method, and throws the TimeoutException exception, the following is breakBarrier()
the code
private void breakBarrier() { generation.broken = true; count = parties; trip.signalAll();}
The broken state is set to true in the code, which means that the current fence removes the damaged state, resets the number of fences, and then wakes up other waiting threads. When the awakened thread or other thread enters the Dowait method, the Brokenbarrierexception exception is thrown
Case source code Address: Github.com/rainbowda/learnway/tree/master/learnconcurrency/src/main/java/com/learnconcurrency/utils/cyclicbarrier
Feel good about a star, thank you.