Java併發——Phaser詳解

Phaser

Phaser中文翻譯爲相位器。它與CountDownLatch非常相似,允許我們協調線程的執行。與CountDownLatch相比,它具有一些額外的功能。

Phaser是在線程動態數需要繼續執行之前等待的屏障。在CountDownLatch中,該數字無法動態配置,需要在創建實例時提供。
在這裏插入圖片描述

arriveAndAwaitAdvanve()方法:
arriveAndAwaitAdvanceo的作用與 CountDownLatch類中的awai()方法大體一樣,通過從方法的名稱解釋來看, arrive是到達的意思,wait是等待的意思,而 advance是前進、促進的意思,所以執行這個方法的作用就是當前線程已經到達屏障,在此等待一段時間,等條件滿足後繼續向下一個屏障繼續執行。

public class PrintTools {
    public static Phaser phaser;

    public static void methodA() {
        System.out.println(Thread.currentThread().getName() + " A1 begin=" + System.currentTimeMillis());
        phaser.arriveAndAwaitAdvance();
        System.out.println(Thread.currentThread().getName() + " A1 end=" + System.currentTimeMillis());

        System.out.println(Thread.currentThread().getName() + " A2 begin=" + System.currentTimeMillis());
        phaser.arriveAndAwaitAdvance();
        System.out.println(Thread.currentThread().getName() + " A2 end=" + System.currentTimeMillis());
    }

    public static void methodB() {
        try {
            System.out.println(Thread.currentThread().getName() + " A1 begin=" + System.currentTimeMillis());
            phaser.arriveAndAwaitAdvance();
            System.out.println(Thread.currentThread().getName() + " A1 end=" + System.currentTimeMillis());

            System.out.println(Thread.currentThread().getName() + " A2 begin=" + System.currentTimeMillis());
            Thread.sleep(5000);
            phaser.arriveAndAwaitAdvance();
            System.out.println(Thread.currentThread().getName() + " A2 end=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Phaser p = new Phaser(3);
        PrintTools.phaser = p;

        ThreadA a = new ThreadA(phaser);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(phaser);
        b.setName("B");
        b.start();

        ThreadC c = new ThreadC(phaser);
        c.setName("C");
        c.start();
    }
}
public class ThreadA extends Thread {
    private Phaser phaser;

    public ThreadA(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        PrintTools.methodA();
    }
}
public class ThreadB extends Thread {
    private Phaser phaser;

    public ThreadB(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        PrintTools.methodA();
    }
}
public class ThreadC extends Thread {
    private Phaser phaser;

    public ThreadC(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        PrintTools.methodB();
    }
}

在這裏插入圖片描述
注意:當arriveAndAwaitAdvance()調用時,如果計數不足,則線層呈阻塞狀態,不繼續向下運行
修改methodB()方法
在這裏插入圖片描述
再次運行,輸出如下:
在這裏插入圖片描述

arriveAndDeregister()方法:
當線程到達屏障後,退出屏障的阻塞,並且使parties值減一。

public class Deregister {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(2);
        MyThread t = new MyThread(phaser);
        t.start();
        System.out.println("main begin" + System.currentTimeMillis());
        System.out.println(phaser.getRegisteredParties());
        phaser.arriveAndDeregister();//退出阻塞,計數-1
        System.out.println(phaser.getRegisteredParties());
        System.out.println("main end" + System.currentTimeMillis());
    }
}

class MyThread extends Thread{
    private Phaser phaser;

    public MyThread(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        phaser.arriveAndAwaitAdvance();
        System.out.println("MyThread end");
    }
}

在這裏插入圖片描述

getPhase()和onAdvance():

方法getPhase()獲取的是已經到達第幾個屏障。

public class getPhase {

    public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new Phaser(1);
        TestThread t = new TestThread(phaser);
        t.start();
    }


}
class TestThread extends Thread {
    private Phaser phaser;

    public TestThread(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        System.out.println("A begin");
        phaser.arriveAndAwaitAdvance();
        System.out.println("A end phase value=" + phaser.getPhase());

        System.out.println("A begin");
        phaser.arriveAndAwaitAdvance();
        System.out.println("A end phase value=" + phaser.getPhase());

        System.out.println("A begin");
        phaser.arriveAndAwaitAdvance();
        System.out.println("A end phase value=" + phaser.getPhase());
    }
}

在這裏插入圖片描述

onAdvance()的作用是通過新的屏障時被調用:

public class onAdvance {
    public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new Phaser(2) {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("onAdvence被調用!");
                return true;
                //返回true表示,下一次到達屏障不等待了,Phaser呈無效/銷燬的狀態
                //返回false表示,下一次到達屏障Phaser繼續工作
            }
        };

        //第一次通過屏障
        AThread a = new AThread(phaser);
        a.start();
        phaser.arriveAndAwaitAdvance();


        //第二次
        Thread.sleep(2000);
        BThread b = new BThread(phaser);
        b.start();
        System.out.println("main end");
    }
}

class AThread extends Thread {
    private Phaser phaser;

    public AThread(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        System.out.println("A begin");
        phaser.arriveAndAwaitAdvance();
        System.out.println("A end");
    }
}

class BThread extends Thread {
    private Phaser phaser;

    public BThread(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        System.out.println("B begin");
        phaser.arriveAndAwaitAdvance();
        System.out.println("B end");
    }
}

onAdvance返回true,下一次到達屏障不阻塞
在這裏插入圖片描述

修改返回值爲false,下一次到達屏障正常阻塞
在這裏插入圖片描述

getRegisteredParities():
獲得註冊的parties數量。

register():
每執行一次方法,就動態添加一個parties值。

bulkRegister():
批量增加parties數量。

getArrivedParties():
獲得已經被使用的parties個數。

getUnarrivedParties():
獲得未被使用的parties個數。

public class Parties {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(5);
        System.out.println(phaser.getRegisteredParties());//5

        phaser.register();
        System.out.println(phaser.getRegisteredParties());//6

        phaser.bulkRegister(10);
        System.out.println(phaser.getRegisteredParties());//16

        System.out.println(phaser.getArrivedParties());//0
        System.out.println(phaser.getUnarrivedParties());//16
    }
}

arrive()方法:
方法arrive()的作用是使parties 值加1,並且不在屏障處等待,直接向下面的代碼繼續運行,並且Phaser類有計數重置功能。

public class TestArrive {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(2){
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("到達屏障,但未通過!phase=" + phase + " registeredParties=" + registeredParties);
                return super.onAdvance(phase, registeredParties);
            }
        };

        System.out.println("A1 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());
        phaser.arrive();
        System.out.println("A1 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());

        System.out.println("A2 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());
        phaser.arrive();
        System.out.println("A2 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());

        System.out.println("B1 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());
        phaser.arrive();
        System.out.println("B1 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());

        System.out.println("B2 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());
        phaser.arrive();
        System.out.println("B2 getPhase=" + phaser.getPhase() + " getRegisteredParties=" + phaser.getRegisteredParties() +
                " getArrivedParties=" + phaser.getArrivedParties());
    }
}

在這裏插入圖片描述
方法arrive()的功能是使getArrivedParties()計數加1,不等待其他線程到達屏障。
在控制檯中多次出現getArrivedParties=0的運行結果,所以可以分析出Phaser類在經過屏障點後計數能被重置。

awaitAdvance(int phase):
如果傳人蔘數phase值和當前getPhase()方法返回值一樣,則在屏障處等待,否則繼續向下面運行,有些類似於旁觀者的作用,當觀察的條件滿足了就等待(旁觀),如果條件不滿足,則程序向下繼續運行。

public class AwaitAdvance {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(1);
        phaser.awaitAdvance(1);//不一樣,通過
        System.out.println("通過第一次");

        phaser.arriveAndAwaitAdvance();
        phaser.awaitAdvance(1);//一樣,阻塞
        System.out.println("通過第二次");
    }
}

在這裏插入圖片描述

awaitAdvanceInterruptibly(int):
可中斷的。
awaitAdvanceInterruptibly(int ,long, TImeUnit):
帶超時,且可中斷。

forceTermination()和isTerminated():
方法forceTermination()使Phaser對象的屏障功能失效,而方法isTerminated()是判斷Phaser對象是否已經呈銷燬狀態。

public class Termination {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(2);
        phaser.forceTermination();
        phaser.arriveAndAwaitAdvance();//失效,所以不阻塞
        System.out.println(phaser.isTerminated());//true
    }
}

控制Phaser類的運行時機

前面的示例都是線程一起到達屏障後繼續運行,有些情況下是需要進行控制的,也就是到達屏障後不允許繼續運行。
默認的運行效果:

public class RunDemo {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(3);
        for (int i = 0; i < 3; i++) {
            RunThread t = new RunThread(phaser);
            t.start();
        }
    }
}

class RunThread extends Thread {
    private Phaser phaser;

    public RunThread(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " A1 begin=" + System.currentTimeMillis());
        phaser.arriveAndAwaitAdvance();
        System.out.println(Thread.currentThread().getName() + " A1 end=" + System.currentTimeMillis());
    }
}

在這裏插入圖片描述

可控的運行時機:

public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new Phaser(3);
        phaser.register();
        for (int i = 0; i < 3; i++) {
            RunThread t = new RunThread(phaser);
            t.start();
        }
        Thread.sleep(2000);
        phaser.arriveAndAwaitAdvance();
    }

在這裏插入圖片描述
此實驗說明運行的時機是可以通過邏輯控制的,主要的原理就是計數+1,然後通過邏輯代碼的方式來決定線程是否繼續向下運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章