JUC tool class Phaser

Posted by bluebyyou on Mon, 20 Sep 2021 04:38:35 +0200

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

Topics: Java Rust