現在有 T1、T2、T3 三個執行緒,怎樣保證 T2 在 T1 執行完後執行T3 在 T2 執行完
阿新 • • 發佈:2020-10-26
問題:現在有T1、T2、T3三個執行緒,你怎樣保證T2在T1執行完後執行,T3在T2執行完後執行
實現:使用Thread中的join方法實現
分析:
Thread
類中的join
方法是用來同步的,底層其實是呼叫了wait
方法。先來看一下演示程式碼:
package com.whh.concurrency; /** *@description: * 問題:現在有 T1、T2、T3 三個執行緒,怎樣保證 T2 在 T1 執行完後執行T3在T2執行完 * 分析:使用join方法實現 *@author:wenhuohuo */ public class MyJoin { public static void main(String[] args) { final Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("執行緒1"); } },"t1"); final Thread t2 = new Thread(new Runnable() { @Override public void run() { try { t1.join(); } catch (Exception e) { e.printStackTrace(); } System.out.println("執行緒2"); } },"t2"); final Thread t3 = new Thread(new Runnable() { @Override public void run() { try { t2.join(); }catch (Exception e){ e.printStackTrace(); } System.out.println("執行緒3"); } },"t3"); t3.start(); t2.start(); t1.start(); } }
執行結果:
執行緒3
執行緒2
執行緒1
可以看到,我們讓t2
執行緒呼叫t1.join
,t3
呼叫t2.join
,儘管是t3,t2,t1分別start,執行順序還是t1,t2,t3。是因為join
方法底層使用的是wait
方法。
- 檢視
join
方法原始碼
public final void join() throws InterruptedException {
join(0); //傳入的是毫秒值
}
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { //isAlive()是native方法,判斷執行緒是否還存活 wait(0); //wait(0),不計時間,一直等待,直到有notify()或notifyAll()來喚醒。 } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay);//傳入時間,表示在時間值消耗完之前一直等待,直到過了等待時間。 now = System.currentTimeMillis() - base; } } }
1)從原始碼中,我們結合之前的程式碼分析,t2.join()
和t3.join()
,均沒有傳值,相當於join(0)
,表示不計時間,t2
會一直wait
等待t1
執行完成,t3
會一直wait
等待t2
執行完成。所以執行結果順序是t3,t2,t1。
2)當傳入的毫秒值不為0時,就一直迴圈等待,直到過了等待時間(dalay<=0),則執行break方法,那麼將不再等待。
- 改變
join()
傳入的毫秒值,檢視執行順序並分析結果:
public class MyJoin { public static void main(String[] args) { final Thread t1 = new Thread(new Runnable() { @Override public void run() { try { //處理業務時間,模擬為8秒 Thread.sleep(8000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("執行緒1"); } },"t1"); final Thread t2 = new Thread(new Runnable() { @Override public void run() { try { t1.join(4000); //t2等待t1執行緒4秒 } catch (Exception e) { e.printStackTrace(); } System.out.println("執行緒2"); } },"t2"); final Thread t3 = new Thread(new Runnable() { @Override public void run() { try { t2.join(2000); //t3等待t2執行緒2秒 }catch (Exception e){ e.printStackTrace(); } System.out.println("執行緒3"); } },"t3"); t3.start(); t2.start(); t1.start(); } }
執行結果:
執行緒3 //程式啟動過了2秒執行t3
執行緒2 //過了4秒執行t2
執行緒1 //過了8秒執行t1
分析:我們讓t1
睡眠8秒模擬業務執行時間,t2等待t1 的時間為4秒,t3等待t2的時間為2秒。那麼當t1,t2,t3啟動後,等待的時間,t3會因為t2的等待時間4秒太長而先與t2執行,t2會因為t1的8秒太長而先與t1執行。