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,然後通過邏輯代碼的方式來決定線程是否繼續向下運行。