多執行緒執行時,如果一個邏輯需要等若干個執行緒執行完成後再執行,怎麼實現?
阿新 • • 發佈:2018-12-14
實際開發過程中,尤其是大型的業務系統中或批量處理系統中,我們通常會用到多執行緒來進行任務拆分,來提高系統的處理能力。當對業務不斷拆分時,多執行緒各自任務之間也形成了錯綜複雜的關係。
我們常常遇到這樣的情況,業務模組A 拆分成了 A1 、A2.....An個多執行緒,來提高處理速度,可是 Ak(1<k<n)這個執行緒執行時,它有依賴關係,它必須等 Ak-1 和Ak-2這兩個程序執行完,才能執行,以免造成業務混亂,那怎麼實現?
我們先定義兩個實現多執行緒任務:
任務1:
public class WorkA1 extends Thread { @Overridepublic 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 voidrun() { 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中的效果一模一樣。