1. 程式人生 > >多執行緒執行時,如果一個邏輯需要等若干個執行緒執行完成後再執行,怎麼實現?

多執行緒執行時,如果一個邏輯需要等若干個執行緒執行完成後再執行,怎麼實現?

實際開發過程中,尤其是大型的業務系統中或批量處理系統中,我們通常會用到多執行緒來進行任務拆分,來提高系統的處理能力。當對業務不斷拆分時,多執行緒各自任務之間也形成了錯綜複雜的關係。

我們常常遇到這樣的情況,業務模組A 拆分成了 A1 、A2.....An個多執行緒,來提高處理速度,可是 Ak(1<k<n)這個執行緒執行時,它有依賴關係,它必須等 Ak-1 和Ak-2這兩個程序執行完,才能執行,以免造成業務混亂,那怎麼實現?

我們先定義兩個實現多執行緒任務:

任務1:

public class WorkA1 extends Thread {
   @Override
   
public void run() { System.out.println("WorkA1 開始執行"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("WorkA1 結束執行"); } }

任務2:

public class WorkA2 extends Thread {
   @Override
   public void 
run() { System.out.println("WorkA2 開始執行"); try { Thread.sleep(1800); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("WorkA2 結束執行"); } }

主執行緒開始實現是這樣的:

public class ThreedClient {
   public static void main(String[] args) {
      System.out
.println("準備開始執行任務"); WorkA1 workA1 = new WorkA1(); WorkA2 workA2 = new WorkA2(); workA1.start(); workA2.start(); System.out.println("執行完成了。"); } }

執行結果是:

準備開始執行任務
執行完成了。
WorkA1 開始執行
WorkA2 開始執行
WorkA2 結束執行
WorkA1 結束執行

如果我們想最後列印 “執行完成了”在所有子執行緒完成後,怎麼辦呢?

我們對主執行緒進行改造:

改造方法1:

public class ThreedClient {
   public static void main(String[] args) {
      System.out.println("準備開始執行任務");
      WorkA1 workA1 = new WorkA1();
      WorkA2 workA2 = new WorkA2();
      workA1.start();
      workA2.start();
      try {
         workA1.join();
         workA2.join();
      }catch (InterruptedException e){
         e.printStackTrace();
      }
      System.out.println("執行完成了。");
   }
}

改造完成後,在看執行結果:

準備開始執行任務
      WorkA2 開始執行
      WorkA1 開始執行
      WorkA2 結束執行
      WorkA1 結束執行
      執行完成了。

OK,達到我們的預期了。

改造方法2:

CountDownLatch允許一個或多個執行緒等待其他執行緒完成操作。CountDownLatch的建構函式接收一個int型別的引數作為計數器,如果你想等待N個點完成,這裡就傳入N。當我們呼叫countDown方法時,N就會減1,await方法會阻塞當前執行緒,直到N變成0。 它的原理很簡單,就是你需要等待幾個任務時,就先定義好,然後任務執行完成一個,計數器減1。看看具體實現:
public class WorkA1 extends Thread {
   private CountDownLatch countDownLatch;
   public WorkA1(CountDownLatch countDownLatch) {
      this.countDownLatch = countDownLatch;
   }
   @Override
   public void run() {
      System.out.println("WorkA1 開始執行");
      try {
         Thread.sleep(2000);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }finally {
         countDownLatch.countDown();
      }
      System.out.println("WorkA1 結束執行");
   }
}

Work2的改造跟Work1完全一樣,就不再單獨貼程式碼了。

看下主執行緒中的改造:

public class ThreedClient {
   public static void main(String[] args) {
      System.out.println("準備開始執行任務");
      CountDownLatch countDownLatch = new CountDownLatch(2);
      WorkA1 workA1 = new WorkA1(countDownLatch);
      WorkA2 workA2 = new WorkA2(countDownLatch);
      workA1.start();
      workA2.start();
      try {
         countDownLatch.await();
      }catch (InterruptedException e){
         e.printStackTrace();
      }
      System.out.println("執行完成了。");
   }
}

 我們看下改造後的執行結果:

準備開始執行任務
WorkA1 開始執行
WorkA2 開始執行
WorkA2 結束執行
WorkA1 結束執行
執行完成了。

跟改造1中的效果一模一樣。