阿裏面試居然跟我扯了半小時的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技術乾貨
