日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java多线程系列:通过对战游戏学习CyclicBarrier

發(fā)布時(shí)間:2024/1/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java多线程系列:通过对战游戏学习CyclicBarrier 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

CyclicBarrier是java.util.concurrent包下面的一個(gè)工具類,字面意思是可循環(huán)使用(Cyclic)的屏障(Barrier),通過它可以實(shí)現(xiàn)讓一組線程到達(dá)一個(gè)屏障(也可以叫同步點(diǎn))時(shí)被阻塞,直到最后一個(gè)線程到達(dá)屏障時(shí),所有被屏障攔截的線程才會(huì)繼續(xù)執(zhí)行。

這篇文章將介紹CyclicBarrier這個(gè)同步工具類的以下幾點(diǎn)

  • 通過案例分析
  • 兩種不同構(gòu)造函數(shù)測(cè)試
  • CyclicBarrier和CountDownLatch的區(qū)別
  • await方法及源碼分析。
  • 需求

    繼上一篇CountDownLatch模擬游戲加載后,現(xiàn)在用戶點(diǎn)擊開始按鈕后,需要匹配包括自己在內(nèi)的五個(gè)玩家才能開始游戲,匹配玩家成功后進(jìn)入到選擇角色階段。當(dāng)5位玩家角色都選擇完畢后,開始進(jìn)入游戲。進(jìn)入游戲時(shí)需要加載相關(guān)的數(shù)據(jù),待全部玩家都加載完畢后正式開始游戲。

    解決方案

    從需求中可以知道,想要開始游戲需要經(jīng)過三個(gè)階段,分別是

  • 匹配玩家
  • 選擇角色
  • 加載數(shù)據(jù)
  • 在這三個(gè)階段中,都需要互相等待對(duì)方完成才能繼續(xù)進(jìn)入下個(gè)階段。?
    這時(shí)可以采用CyclicBarrier來作為各個(gè)階段的節(jié)點(diǎn),等待其他玩家到達(dá),在進(jìn)入下個(gè)階段。

    ?

    ?

    定義繼承Runnable的類

    這里名稱就叫做StartGame,包含兩個(gè)屬性

    private String player; private CyclicBarrier barrier;

    通過構(gòu)造函數(shù)初始化兩個(gè)屬性

    public StartGame(String player, CyclicBarrier barrier) {this.player = player;this.barrier = barrier; }

    run方法如下

    public void run() {try {System.out.println(this.getPlayer()+" 開始匹配玩家...");findOtherPlayer();barrier.await();System.out.println(this.getPlayer()+" 進(jìn)行選擇角色...");choiceRole();System.out.println(this.getPlayer()+" 角色選擇完畢等待其他玩家...");barrier.await();System.out.println(this.getPlayer()+" 開始游戲,進(jìn)行游戲加載...");loading();System.out.println(this.getPlayer()+" 游戲加載完畢等待其他玩家加載完成...");barrier.await();start();} catch (Exception e){e.printStackTrace();} }

    其他的方法findOtherPlayer()、choiceRole()等待使用

    Thread.sleep()

    來模擬花費(fèi)時(shí)間

    編寫測(cè)試代碼

    CyclicBarrier有兩個(gè)構(gòu)造函數(shù),如下

    public CyclicBarrier(int parties) {} public CyclicBarrier(int parties, Runnable barrierAction) {}

    先來看看一個(gè)參數(shù)的構(gòu)造函數(shù)

    CyclicBarrier(int parties)

    public static void main(String[] args) throws IOException {CyclicBarrier barrier = new CyclicBarrier(5);Thread player1 = new Thread(new StartGame("1",barrier));Thread player2 = new Thread(new StartGame("2",barrier));Thread player3 = new Thread(new StartGame("3",barrier));Thread player4 = new Thread(new StartGame("4",barrier));Thread player5 = new Thread(new StartGame("5",barrier));player1.start();player2.start();player3.start();player4.start();player5.start();System.in.read(); }

    測(cè)試結(jié)果如下

    ?

    ?

    CyclicBarrier(int parties, Runnable barrierAction)

    CyclicBarrier barrier = new CyclicBarrier(5);

    替換為

    CyclicBarrier barrier = new CyclicBarrier(5, () -> {try {System.out.println("階段完成,等待2秒...");Thread.sleep(2000);System.out.println("進(jìn)入下個(gè)階段...");} catch (InterruptedException e) {e.printStackTrace();}});

    再來看看效果

    ?

    ?

    可以看到在到達(dá)某個(gè)節(jié)點(diǎn)時(shí),會(huì)執(zhí)行實(shí)例化CyclicBarrier時(shí)傳入的Runnable對(duì)象。而且每一次到達(dá)都會(huì)執(zhí)行一次。

    CyclicBarrier和CountDownLatch的區(qū)別

    await方法

    public int await(){} public int await(long timeout, TimeUnit unit){}

    無(wú)參的await方法這里就不做介紹了,主要介紹下有參的await方法。?
    有參的await方法傳入兩個(gè)參數(shù),一個(gè)是時(shí)間、另一個(gè)是時(shí)間單位?
    當(dāng)調(diào)用有參的await方法時(shí)會(huì)出現(xiàn)下方兩個(gè)異常

    java.util.concurrent.TimeoutException java.util.concurrent.BrokenBarrierException

    TimeoutException異常是指調(diào)用await方法后等待時(shí)間超過傳入的時(shí)間,此時(shí)會(huì)將CyclicBarrier的狀態(tài)變成broken,其他調(diào)用await方法將會(huì)拋出BrokenBarrierException異常,這時(shí)的CyclicBarrier將變得不可用,需要調(diào)用reset()方法重置CyclicBarrier的狀態(tài)。

    為什么這么說??
    源碼分析一波就可以看出來了?
    不管是有參還是無(wú)參的await方法都是調(diào)用CyclicBarrier的dowait(boolean timed, long nanos)方法,這個(gè)方法代碼太長(zhǎng)了,截取部分貼出來

    private int dowait(boolean timed, long nanos){//加鎖、try catch代碼final Generation g = generation;//判斷柵欄的狀態(tài)if (g.broken)throw new BrokenBarrierException();//...省略int index = --count;//(index == 0) 時(shí)的代碼,省略for (;;) {try {if (!timed)trip.await();else if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {}//判斷柵欄的狀態(tài)if (g.broken)throw new BrokenBarrierException();if (g != generation)return index;//判斷是否是定時(shí)的,且已經(jīng)超時(shí)了if (timed && nanos <= 0L) {//打破柵欄的狀態(tài)breakBarrier();throw new TimeoutException();}}//解鎖 }

    在代碼的尾部進(jìn)行判斷當(dāng)前等待是否已經(jīng)超時(shí),如果是會(huì)調(diào)用breakBarrier()方法,且拋出TimeoutException異常,下面是breakBarrier()的代碼

    private void breakBarrier() {generation.broken = true;count = parties;trip.signalAll(); }

    代碼中將broken狀態(tài)置為true,表示當(dāng)前柵欄移除損壞狀態(tài),且重置柵欄數(shù)量,然后喚醒其他等待的線程。此時(shí)被喚醒的線程或者其他線程進(jìn)入dowait方法時(shí),都會(huì)拋出BrokenBarrierException異常

    案例源代碼地址:https://github.com/rainbowda/learnWay/tree/master/learnConcurrency/src/main/java/com/learnConcurrency/utils/cyclicBarrier

    覺得不錯(cuò)的點(diǎn)個(gè)Star,謝謝!

    總結(jié)

    以上是生活随笔為你收集整理的java多线程系列:通过对战游戏学习CyclicBarrier的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。