Java模擬賽跑過程

monkeysayhi發表於2017-11-27

Java併發面試中的一個經典問題——手寫程式碼模擬賽跑過程。該問題考查CountDownLatch的用法,比Java實現生產者-消費者模型的考查更直接:

  • 對Java併發模型的理解
  • 對Java併發程式設計介面(CountDownLatch)的熟練程度
  • 簡化問題的能力
  • bug free
  • coding style

JDK版本:oracle java 1.8.0_102

需要注意是“簡化問題的能力”。建議讀者在繼續閱讀之前,自己先實現一個版本,之後再與文中的程式碼比較,看哪種思路更簡潔,實現更美觀。

需求

問題很經典,則需求概括如下:

  • 所有選手就位後,裁判鳴槍開始比賽
  • 選手到達終點或中途退賽後,記錄成績
  • 所有選手都已記錄成績後,結束比賽

再次建議讀者自己先實現一個版本,再繼續閱讀。

設計 && 實現

設計

題目描述很清晰,現簡化需求並設計如下:

選手逐漸就位 -> 開始比賽 -> 選手逐漸跑到終點或發生異常 -> 比賽結束複製程式碼

在三個連線處各使用一個CountDownLatch即可。

實現

三個連線處分別命名為ready、start、end,參賽者數量racerCnt,則:

public class Race {

  public static void race(int racerCnt) throws InterruptedException {
    CountDownLatch ready = new CountDownLatch(racerCnt);
    CountDownLatch start = new CountDownLatch(1);
    CountDownLatch end = new CountDownLatch(racerCnt);

    for (int i = 0; i < racerCnt; i++) {
      final int racerNo = i;
      new Thread(new Runnable() {
        @Override
        public void run() {
          System.out.println("ready: " + racerNo);
          ready.countDown();
          try {
            start.await();
            System.out.println("start: " + racerNo);
          } catch (InterruptedException e) {
            System.out.println("I am hurt, and have to interrupt the race...");
            Thread.currentThread().interrupt();
          } finally {
            System.out.println("end: " + racerNo);
            end.countDown();
          }
        }
      }).start();
    }

    ready.await();
    System.out.println("********************** all ready!!! **********************");
    System.out.println("********************** will start soon **********************");
    start.countDown();
    end.await();
    System.out.println("********************** all end!!! **********************");
  }

  public static void main(String[] args) throws InterruptedException {
    race(5);
  }
}複製程式碼

選擇一個比較亂的輸出:

ready: 1
ready: 0
ready: 2
ready: 3
ready: 4
********************** all ready!!! **********************
********************** will start soon **********************
start: 1
start: 2
start: 3
end: 3
start: 0
end: 0
end: 2
end: 1
start: 4
end: 4
********************** all end!!! **********************複製程式碼

很明顯:第一名是3號選手;最後一名是4號選手;3號跑完的時候,0號還沒有開跑。

總結

用CountDownLatch模擬賽跑過程雖然簡單,但能簡潔、美觀的實現卻不容易,很考驗面試者簡化問題的能力。


本文連結:Java模擬賽跑過程
作者:猴子007
出處:monkeysayhi.github.io
本文基於 知識共享署名-相同方式共享 4.0 國際許可協議釋出,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名及連結。