阿裏面試居然跟我扯了半小時的CyclicBarrier

一個大腹便便,穿着格子襯衫的中年男子,拿着一個貼滿Logo的Mac向我走來,看着稀少的頭髮,我心想着肯定是頂級技術大牛吧!但是我也是一個才華橫溢的人,穩住我們能贏。

面試官:您好,先做一下自我介紹吧!

:您好,我是亞瑟,王者背負,王者審判,王者不可阻擋!

面試官:用什麼銘文?怎麼出裝嗎?

:咳咳咳,不好意思,說錯了。我是萬貓,一直在做Java的後端開發。

面試官:咳咳咳,看你簡歷上寫熟悉並發編程,CyclicBarrier用過的吧?

:有用過。(還好提前有準備!)

面試官:它的主要作用是什麼?

:CyclicBarrier是一種同步輔助工具,字面意思就是循環柵欄,它允許一組線程在一個共同的屏障點彼此等待,所有線程到達屏障點後再全部同時執行。固定數量的線程在程序中必須彼此等待的時候,CyclicBarrier非常有用。

面試官:為什麼叫循環柵欄?循環是什麼含義?

:循環是因為當所有等待線程都被釋放以後,CyclicBarrier可以被重用。

面試官:可以舉一個重用的例子嗎?

:比如張三、李四和王五三個人約好去飯店一起去吃飯,等到所有人到了飯店以後再一起吃飯,然後等到所有人都吃完以後再一起離開餐廳。這兩次等待就可以重用。

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

面試官:可以寫一下嗎?

:當然可以,這是人物的類:

package onemore.study;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.CyclicBarrier;

public class Person implements Runnable {
    private CyclicBarrier barrier;
    private String name;

    public Person(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }

    @Override
    public void run() {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
            Random random = new Random();

            System.out.println(sdf.format(new Date()) + " " + name + "出發去飯店");
            Thread.sleep((long)(random.nextDouble() * 3000) + 1000);
            System.out.println(sdf.format(new Date()) + " " + name + "到了飯店");

            barrier.await();

            System.out.println(sdf.format(new Date()) + " " + name + "開始吃飯");
            Thread.sleep((long)(random.nextDouble() * 3000) + 1000);
            System.out.println(sdf.format(new Date()) + " " + name + "吃完了");

            //重用CyclicBarrier
            barrier.await();

            System.out.println(sdf.format(new Date()) + " " + name + "離開餐廳");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然後這是測試類:

package onemore.study;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTester {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(3);

        List<Thread> threads = new ArrayList<>(3);
        threads.add(new Thread(new Person(barrier, "張三")));
        threads.add(new Thread(new Person(barrier, "李四")));
        threads.add(new Thread(new Person(barrier, "王五")));

        for (Thread thread : threads) {
            thread.start();
        }

        //等待所有線程跑完
        for (Thread thread : threads) {
            thread.join();
        }
    }
}

運行以後的結果應該是這樣的:

07:15:58.856 張三出發去飯店
07:15:58.856 王五齣發去飯店
07:15:58.856 李四齣發去飯店
07:16:01.237 李四到了飯店
07:16:02.039 王五到了飯店
07:16:02.600 張三到了飯店
07:16:02.600 張三開始吃飯
07:16:02.600 李四開始吃飯
07:16:02.600 王五開始吃飯
07:16:04.620 張三吃完了
07:16:05.046 王五吃完了
07:16:05.145 李四吃完了
07:16:05.145 李四離開餐廳
07:16:05.145 張三離開餐廳
07:16:05.145 王五離開餐廳

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

面試官:有沒有看過CyclicBarrier的源碼?

:看過JDK8的一些源碼。

面試官:那說說CyclicBarrier被障礙的原理。

:在CyclicBarrier的內部定義了一個ReentrantLock的對象,然後再利用這個ReentrantLock對象生成一個Condition的對象。每當一個線程調用CyclicBarrier的await方法時,首先把剩餘屏障的線程數減1,然後判斷剩餘屏障數是否為0:如果不是,利用Condition的await方法阻塞當前線程;如果是,首先利用Condition的signalAll方法喚醒所有線程,最後重新生成Generation對象以實現屏障的循環使用。

面試官:嗯,我這裡沒有要問的了。你稍等一會,我去叫下一個面試官。

微信公眾號:萬貓學社

微信掃描二維碼

獲得更多Java技術乾貨

Tags: