Java多線程中的Phaser使用解析
問題描述
java多線程技術(shù)提供了Phaser工具類,Phaser表示“階段器”,用來解決控制多個(gè)線程分階段共同完成任務(wù)的情景問題。
其作用相比CountDownLatch和CyclicBarrier更加靈活,例如有這樣的一個(gè)題目:
5個(gè)學(xué)生一起參加考試,一共有三道題,要求所有學(xué)生到齊才能開始考試,全部同學(xué)都做完第一題,學(xué)生才能繼續(xù)做第二題,全部學(xué)生做完了第二題,才能做第三題,所有學(xué)生都做完的第三題,考試才結(jié)束。
分析這個(gè)題目:這是一個(gè)多線程(5個(gè)學(xué)生)分階段問題(考試考試、第一題做完、第二題做完、第三題做完),所以很適合用Phaser解決這個(gè)問題。
實(shí)現(xiàn)代碼
import java.util.concurrent.Phaser; /*** * 下面說說Phaser的高級(jí)用法,在Phaser內(nèi)有2個(gè)重要狀態(tài),分別是phase和party。 * phase就是階段,初值為0,當(dāng)所有的線程執(zhí)行完本輪任務(wù),同時(shí)開始下一輪任務(wù)時(shí), * 意味著當(dāng)前階段已結(jié)束,進(jìn)入到下一階段,phase的值自動(dòng)加1。party就是線程, * party=4就意味著Phaser對(duì)象當(dāng)前管理著4個(gè)線程。Phaser還有一個(gè)重要的方法經(jīng)常需要被重載, * 那就是boolean onAdvance(int phase, int registeredParties)方法。此方法有2個(gè)作用: * 1、當(dāng)每一個(gè)階段執(zhí)行完畢,此方法會(huì)被自動(dòng)調(diào)用,因此,重載此方法寫入的代碼會(huì)在每個(gè)階段執(zhí)行完畢時(shí)執(zhí)行, * 相當(dāng)于CyclicBarrier的barrierAction。 * 2、當(dāng)此方法返回true時(shí),意味著Phaser被終止,因此可以巧妙的設(shè)置此方法的返回值來終止所有線程。 * @author liujun */ public class MyPhaser extends Phaser { @Override protected boolean onAdvance(int phase, int registeredParties) { //在每個(gè)階段執(zhí)行完成后回調(diào)的方法 switch (phase) { case 0: return studentArrived(); case 1: return finishFirstExercise(); case 2: return finishSecondExercise(); case 3: return finishExam(); default: return true; } } private boolean studentArrived(){ System.out.println("學(xué)生準(zhǔn)備好了,學(xué)生人數(shù):"+getRegisteredParties()); return false; } private boolean finishFirstExercise(){ System.out.println("第一題所有學(xué)生做完"); return false; } private boolean finishSecondExercise(){ System.out.println("第二題所有學(xué)生做完"); return false; } private boolean finishExam(){ System.out.println("第三題所有學(xué)生做完,結(jié)束考試"); return true; } }
import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; public class StudentTask implements Runnable { private Phaser phaser; public StudentTask(Phaser phaser) { this.phaser = phaser; } @Override public void run() { System.out.println(Thread.currentThread().getName()+"到達(dá)考試"); phaser.arriveAndAwaitAdvance(); System.out.println(Thread.currentThread().getName()+"做第1題時(shí)間..."); doExercise1(); System.out.println(Thread.currentThread().getName()+"做第1題完成..."); phaser.arriveAndAwaitAdvance(); System.out.println(Thread.currentThread().getName()+"做第2題時(shí)間..."); doExercise2(); System.out.println(Thread.currentThread().getName()+"做第2題完成..."); phaser.arriveAndAwaitAdvance(); System.out.println(Thread.currentThread().getName()+"做第3題時(shí)間..."); doExercise3(); System.out.println(Thread.currentThread().getName()+"做第3題完成..."); phaser.arriveAndAwaitAdvance(); } private void doExercise1() { long duration = (long)(Math.random()*10); try { TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } private void doExercise2() { long duration = (long)(Math.random()*10); try { TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } private void doExercise3() { long duration = (long)(Math.random()*10); try { TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } }
/** * 題目:5個(gè)學(xué)生參加考試,一共有三道題,要求所有學(xué)生到齊才能開始考試 * ,全部做完第一題,才能繼續(xù)做第二題,后面類似。 * * Phaser有phase和party兩個(gè)重要狀態(tài), * phase表示階段,party表示每個(gè)階段的線程個(gè)數(shù), * 只有每個(gè)線程都執(zhí)行了phaser.arriveAndAwaitAdvance(); * 才會(huì)進(jìn)入下一個(gè)階段,否則阻塞等待。 * 例如題目中5個(gè)學(xué)生(線程)都條用phaser.arriveAndAwaitAdvance();就進(jìn)入下一題 * @author liujun */ public class Main { public static void main(String[] args) { MyPhaser phaser = new MyPhaser(); StudentTask[] studentTask = new StudentTask[5]; for (int i = 0; i < studentTask.length; i++) { studentTask[i] = new StudentTask(phaser); phaser.register(); //注冊(cè)一次表示phaser維護(hù)的線程個(gè)數(shù) } Thread[] threads = new Thread[studentTask.length]; for (int i = 0; i < studentTask.length; i++) { threads[i] = new Thread(studentTask[i], "Student "+i); threads[i].start(); } //等待所有線程執(zhí)行結(jié)束 for (int i = 0; i < studentTask.length; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Phaser has finished:"+phaser.isTerminated()); } }
結(jié)果
Student 0到達(dá)考試
Student 1到達(dá)考試
Student 4到達(dá)考試
Student 2到達(dá)考試
Student 3到達(dá)考試
學(xué)生準(zhǔn)備好了5
Student 2做第1題時(shí)間...
Student 0做第1題時(shí)間...
Student 1做第1題時(shí)間...
Student 4做第1題時(shí)間...
Student 3做第1題時(shí)間...
Student 2做第1題完成...
Student 3做第1題完成...
Student 1做第1題完成...
Student 0做第1題完成...
Student 4做第1題完成...
第一題所有學(xué)生做完
Student 3做第2題時(shí)間...
Student 0做第2題時(shí)間...
Student 4做第2題時(shí)間...
Student 1做第2題時(shí)間...
Student 2做第2題時(shí)間...
Student 3做第2題完成...
Student 2做第2題完成...
Stud ent 0做第2題完成...
Student 1做第2題完成...
Student 4做第2題完成...
第二題所有學(xué)生做完
Student 0做第3題時(shí)間...
Student 3做第3題時(shí)間...
Student 2做第3題時(shí)間...
Student 4做第3題時(shí)間...
Student 1做第3題時(shí)間...
Student 1做第3題完成...
Student 0做第3題完成...
Student 2做第3題完成...
Student 3做第3題完成...
Student 4做第3題完成...
第三題所有學(xué)生做完,結(jié)束考試
Phaser has finished:true
到此這篇關(guān)于Java多線程中的Phaser使用解析的文章就介紹到這了,更多相關(guān)Java多線程中的Phaser內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatisPlus中批量插入之如何通過開啟rewriteBatchedStatements=true
這篇文章主要介紹了MyBatisPlus中批量插入之如何通過開啟rewriteBatchedStatements=true問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03java使用HashMap實(shí)現(xiàn)斗地主(有序版)
這篇文章主要為大家詳細(xì)介紹了java使用ArrayList實(shí)現(xiàn)斗地主游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03spring?boot自動(dòng)裝配之@ComponentScan注解用法詳解
@ComponentScan的作用就是根據(jù)定義的掃描路徑,把符合掃描規(guī)則的類裝配到spring容器中,下面這篇文章主要給大家介紹了關(guān)于spring?boot自動(dòng)裝配之@ComponentScan注解用法的相關(guān)資料,需要的朋友可以參考下2023-04-04只用400行Java代碼就能實(shí)現(xiàn)的飛翔的小鳥游戲
今天給大家?guī)淼氖顷P(guān)于Java實(shí)戰(zhàn)的相關(guān)知識(shí),文章圍繞著只用400行Java代碼就能實(shí)現(xiàn)的飛翔的小鳥游戲展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06Java計(jì)時(shí)器StopWatch實(shí)現(xiàn)方法代碼實(shí)例
這篇文章主要介紹了Java計(jì)時(shí)器StopWatch實(shí)現(xiàn)方法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07Java任意長度byte數(shù)組轉(zhuǎn)換為int數(shù)組的方法
這篇文章主要給大家介紹了關(guān)于Java任意長度byte數(shù)組轉(zhuǎn)換為int數(shù)組的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07