1. 程式人生 > 程式設計 >Java併發程式設計入門(十五)CyclicBarrier應用場景

Java併發程式設計入門(十五)CyclicBarrier應用場景

Java極客  |  作者  /  鏗然一葉
這是Java極客的第 43 篇原創文章

一、應用場景

現實生活做中有很多這樣的場景:做F前需要等待A,B,C,D,E完成,A,E可以併發完成,沒有特定順序,並且F做完後又重新開始,例如:組裝汽車前需要先生產輪胎,車門,車身等等。這個場景的特徵為:

1.組裝汽車前有N件事情要做,每件事情都做完後才能組裝汽車。

2.每件事情可以並行處理,沒有先後順序,因而提高了效率。

3.組裝好一輛汽車後繼續生產和組裝下一輛。(當然現在所有零件都是批量生產,不是一個個來的,我們假設是人工造的限量版賓利,一量量來的。)

圍繞造車,整個過程如下:


在應用程式中處理並行操作時也跟上述場景類似,碰到這種場景時可以通過java併發工具CyclicBarrier來實現。

二、Show me code

程式碼類結構如下:

I、MakeCarBody.java

public class MakeCarBody implements Runnable {

    private CyclicBarrier cyclicBarrier;

    public MakeCarBody(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    public void run() {
        exec();
    }

    /**
     * 模擬模擬造車身
     */
private void exec() { //造完後繼續造下一個 while(true) { try { System.out.println("Start making car body..."); long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000; TimeUnit.MILLISECONDS.sleep(millis); System.out.println("Making car body is finished."
); //等待其他部件造完 this.cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } } 複製程式碼

II、MakeCarDoor.java

public class MakeCarDoor implements Runnable {

    private CyclicBarrier cyclicBarrier;

    public MakeCarDoor(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    public void run() {
        exec();
    }

    /**
     * 模擬造車門
     */
    private void exec() {
        //造完後繼續造下一個
        while(true) {
            try {
                System.out.println("Start making car door...");

                long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000;
                TimeUnit.MILLISECONDS.sleep(millis);
                System.out.println("Making car door is finished.");

                //等待其他部件造完
                this.cyclicBarrier.await();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}
複製程式碼

III、MakeTire.java

public class MakeTire implements Runnable {

    private CyclicBarrier cyclicBarrier;

    public MakeTire(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    public void run() {
        exec();
    }

    /**
     * 模擬造輪胎
     */
    private void exec() {
        //造完後繼續造下一個
        while(true) {
            try {
                System.out.println("Start making tire...");

                long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000;
                TimeUnit.MILLISECONDS.sleep(millis);
                System.out.println("Making tire is finished.");

                //等待其他部件造完
                this.cyclicBarrier.await();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}
複製程式碼

IV、AssembleCar.java

public class AssembleCar implements Runnable {

    public void run() {
        try {
            System.out.println("Start assemble car...");

            //模擬組裝汽車
            long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
            TimeUnit.MILLISECONDS.sleep(millis);
            System.out.println("Making assemble care is finished.");
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

V、CyclicBarrierTest.java

public class CyclicBarrierTest {
    public static void main(String[] args) {
        //有3個部件要造,造完後組裝汽車
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3,new AssembleCar());

        Thread makeCarBody = new Thread(new MakeCarBody(cyclicBarrier));
        Thread makeCarDoor = new Thread(new MakeCarDoor(cyclicBarrier));
        Thread makeTire = new Thread(new MakeTire(cyclicBarrier));

        makeCarBody.start();
        makeCarDoor.start();
        makeTire.start();
    }
}
複製程式碼

輸出日誌:

Start making car door...
Start making tire...
Start making car body...
Making tire is finished.
Making car door is finished.
Making car body is finished.
Start assemble car...
Making assemble care is finished.
Start making car body...
Start making tire...
Start making car door...
Making car body is finished.
Making tire is finished.
Making car door is finished.
Start assemble car...
Making assemble care is finished.
複製程式碼

可以看到CyclicBarrier的使用方式如下:

1.CyclicBarrier的建構函式有2個引數,第1個引數是宣告有幾個部件需要製造(有幾件事可以並行),第2個引數是一個Runnable,此引數代表並行完之後要做的最後一件事情。

2.每個部件造完後呼叫CyclicBarrier的await()方法等待啟動下一輪。

3.當最後一個部件造完後則會自動呼叫CyclicBarrier建構函式中傳入的Runnable的實現類。

4.Runnable實現類實現完成後重新開始下一輪。

三、總結

CyclicBarrier的適用場景:

1.幾件事情完成之後才能開始另外一件事情。

2.需要做的幾件事情可以獨立完成,並且可以並行處理。

3.以上事情完成後繼續下一輪處理。

end.


相關閱讀:
Java併發程式設計(一)知識地圖
Java併發程式設計(二)原子性
Java併發程式設計(三)可見性
Java併發程式設計(四)有序性
Java併發程式設計(五)建立執行緒方式概覽
Java併發程式設計入門(六)synchronized用法
Java併發程式設計入門(七)輕鬆理解wait和notify以及使用場景
Java併發程式設計入門(八)執行緒生命週期
Java併發程式設計入門(九)死鎖和死鎖定位
Java併發程式設計入門(十)鎖優化
Java併發程式設計入門(十一)限流場景和Spring限流器實現
Java併發程式設計入門(十二)生產者和消費者模式-程式碼模板
Java併發程式設計入門(十三)讀寫鎖和快取模板
Java併發程式設計入門(十四)CountDownLatch應用場景
Java併發程式設計入門(十六)秒懂執行緒池差別
Java併發程式設計入門(十七)一圖掌握執行緒常用類和介面
Java併發程式設計入門(十八)再論執行緒安全