brief introduction
Java 7 introduces a new reusable synchronization barrier, Phaser phaser, which is similar to CyclicBarrier and CountDownLatch, but more powerful.
CyclicBarrier solves the problem that CountDownLatch cannot be reused, but it still has the following shortcomings:
1) The counter value cannot be dynamically adjusted. If the number of threads is not enough to break the barrier, you can only reset or add more threads, which is obviously unrealistic in practical application
2) Each await consumes only one counter value, which is not flexible enough
Phaser is used to solve these problems. Phaser divides the tasks executed by multiple threads into multiple stages. Each stage can have any participant. Threads can register and participate in a stage at any time.
Common methods of Phaser
1. register method
Add a party dynamically
int register()
2. bulkRegister method
Dynamically add multiple parties
Parties: the number of parties to be added
int bulkRegister(int parties)
3. getRegisteredParties method
Get the current number of parties
int getRegisteredParties()
4. arriveAndAwaitAdvance method
Arrive and wait for other threads to arrive
int arriveAndAwaitAdvance()
5. arriveAndDeregister method
Arrive at and log out of the parties. This method will not block the thread
int arriveAndDeregister()
6. arrive method
Arrives, but does not block the thread
int arrive()
7. awaitAdvance method
Wait for the line to move forward. It can be blocked or not. The judgment condition is whether the incoming phase is the phase of the current phaser. If it is equal, it will block, otherwise it will not block
Phase: phase value
int awaitAdvance(int phase)
8. Awaitadvanceinterruptible method
This method is similar to awaitAdvance, except that it can interrupt.
Phase: phase value
Timeout: timeout
Unit: time unit
int awaitAdvanceInterruptibly(int phase)
int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)
9. getArrivedParties method
Gets the number of parties currently arriving
int getArrivedParties()
10. getUnarrivedParties method
Gets the number of parties that have not yet arrived
int getUnarrivedParties()
11. getPhase method
Gets the current phase, starting from 0 by default, and the maximum value is the maximum value of integer
int getPhase()
12. isTerminated method
Judge whether the current phaser is closed
boolean isTerminated()
13. forceTermination method
Force close current phaser
void forceTermination()
Demonstration of common methods
package com.dongguo.juc; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; /** * @author Dongguo * @date 2021/9/19 0019-13:26 * @description: */ public class PhaserTest2 { public static void main(String[] args) throws InterruptedException { //Initialize 5 parties Phaser phaser = new Phaser(5); //Only when all threads pass will it enter the next stage, starting from 0 System.out.println("Number of current stages:"+phaser.getPhase()); //Add a party phaser.register(); System.out.println("current Parties Number:"+phaser.getRegisteredParties()); //Add multiple parties phaser.bulkRegister(4); System.out.println("current Parties Number:"+phaser.getRegisteredParties()); new Thread(()->{ //Arrive and wait for other threads to arrive phaser.arriveAndAwaitAdvance(); },"t1").start(); new Thread(()->{ //Log out of the parties after arrival without waiting for other threads phaser.arriveAndDeregister(); System.out.println("go on"); },"t2").start(); TimeUnit.MILLISECONDS.sleep(100); System.out.println("current Parties Number:"+phaser.getRegisteredParties()); System.out.println("Current arrivals:"+phaser.getArrivedParties()); System.out.println("Current outstanding:"+phaser.getUnarrivedParties()); //When it will stop, it will stop only when the number in the parties is 0 or when the forceTermination method is called. We can also override onAdvance in the phaser and return true to stop the phaser System.out.println("phaser End:"+phaser.isTerminated()); phaser.forceTermination(); System.out.println("phaser End:"+phaser.isTerminated()); } } Operation results Number of current stages: 0 current Parties Number: 6 current Parties Number: 10 go on current Parties Number: 9 Current arrivals: 1 Current outstanding: 8 phaser End: false phaser End: true
case
Registering parties dynamically using Phaser
package com.dongguo.juc; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; /** * @author Dongguo * @date 2021/9/19 0019-11:40 * @description:5 All the workers finished their work at the same time */ public class PhaserTest { private static Phaser phaser = new Phaser(); public static void main(String args[]) { for (int i = 1; i <= 5; i++) { new Thread(()->{ phaser.register(); System.out.println(Thread.currentThread().getName() +" is working"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } phaser.arriveAndAwaitAdvance();//wait for System.out.println(Thread.currentThread().getName() +" work finished "+System.currentTimeMillis()); },"t"+i).start(); } } } Operation results t1 is working t3 is working t2 is working t4 is working t5 is working t4 work finished 1632029871265 t5 work finished 1632029871265 t2 work finished 1632029871265 t1 work finished 1632029871265 t3 work finished 1632029871265
Setting up multiple phases using Phaser
package com.dongguo.juc; import java.util.Random; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; /** * @author Dongguo * @date 2021/9/19 0019-12:42 * @description: Simulate three athletes to participate in three sports together */ public class PhaserTest1 { public static void main(String[] args) { Phaser phaser = new Phaser(3); for (int i = 1; i <= 3; i++) { int no =i; new Thread(() -> { try { System.out.println(no+": Currently in the second stage:"+phaser.getPhase()+"stage"); System.out.println(no+": start running"); TimeUnit.SECONDS.sleep(2); System.out.println(no+": end running"); //Wait for other athletes to finish running phaser.arriveAndAwaitAdvance(); System.out.println(no+": Currently in the second stage:"+phaser.getPhase()+"stage"); System.out.println(no+": start bicycle"); TimeUnit.SECONDS.sleep(2); System.out.println(no+": end bicycle"); //Wait for other athletes to complete the ride phaser.arriveAndAwaitAdvance(); System.out.println(no+": Currently in the second stage:"+phaser.getPhase()+"stage"); System.out.println(no+": start long jump"); TimeUnit.SECONDS.sleep(2); System.out.println(no+": end long jump"); //Wait for other athletes to finish the long jump phaser.arriveAndAwaitAdvance(); } catch (Exception e) { e.printStackTrace(); } }, "t"+i).start(); } } } Operation results 1: Currently in stage: 0 2: Currently in stage: 0 2: start running 1: start running 3: Currently in stage: 0 3: start running 2: end running 1: end running 3: end running 3: Currently in phase: 1 3: start bicycle 1: Currently in phase: 1 2: Currently in phase: 1 1: start bicycle 2: start bicycle 1: end bicycle 2: end bicycle 3: end bicycle 1: Currently in phase: 2 1: start long jump 3: Currently in phase: 2 3: start long jump 2: Currently in phase: 2 2: start long jump 1: end long jump 3: end long jump 2: end long jump
summary
Phaser can dynamically increase or decrease the registration amount through register() method and arriveAndDeregister() method
Use arriveAndAwaitAdvance, which is equivalent to the CyclicBarrier mechanism
Use arrive, which is equivalent to the countdown mechanism
You can use awaitAdvance to make the main thread wait for the child threads to complete the task