join方法,一種特殊的wait,當前運行線程調用另外一個線程的join方法,當前線程進入阻塞狀態直到調用join方法的線程結束,再繼續執行。html
通常狀況下,都是主線程建立一個子線程,子線程調用join方法,主線程會進入阻塞狀態,直到子線程運行結束。git
public class JoinThreadDemo { public static void main(String[] args) { JoinRunnable runnable1 = new JoinRunnable(); Thread thread1 = new Thread(runnable1, "線程1"); System.out.println("主線程開始執行!"); thread1.start(); // try { // thread1.join(); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println("主線程執行結束!"); } static final class JoinRunnable implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + "開始執行!"); for (int i = 1; i <= 5; i++) { System.out.println(name + "執行了[" + i + "]次"); } } } }
Output:github
主線程開始執行! 主線程執行結束! 線程1開始執行! 線程1執行了[1]次 線程1執行了[2]次 線程1執行了[3]次 線程1執行了[4]次 線程1執行了[5]次
取消註釋,調用join方法:多線程
主線程開始執行! 線程1開始執行! 線程1執行了[1]次 線程1執行了[2]次 線程1執行了[3]次 線程1執行了[4]次 線程1執行了[5]次 主線程執行結束!
public class JoinThreadDemo { public static void main(String[] args) { JoinRunnable runnable1 = new JoinRunnable(); Thread thread1 = new Thread(runnable1, "線程1"); System.out.println("主線程開始執行!"); thread1.start(); try { synchronized (thread1) { while (thread1.isAlive()) { System.out.println("begin wait"); //主線程持有thread1對象鎖,阻塞,一直到thread1運行結束,jvm喚醒 thread1.wait(0); System.out.println("thread wait"); } } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主線程執行結束!"); } static final class JoinRunnable implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + "開始執行!"); for (int i = 1; i <= 5; i++) { System.out.println(name + "執行了[" + i + "]次"); } } } }
Output:jvm
主線程開始執行! begin wait 線程1開始執行! 線程1執行了[1]次 線程1執行了[2]次 線程1執行了[3]次 線程1執行了[4]次 線程1執行了[5]次 thread wait 主線程執行結束!
在thread1
調用wait
後,主線程阻塞,一直到子線程thread1
運行結束退出之後,jvm
會自動喚醒阻塞在thread1
對象上的線程ide
那麼有沒有可能不使用thread1
對象阻塞呢?post
下面就是不使用thread1
對象阻塞主線程的案例.net
public class JoinThreadDemo { public static void main(String[] args) { Object lock = new Object(); Thread thread1 = new Thread(() -> { String name = Thread.currentThread().getName(); System.out.println(name + "開始執行!"); for (int i = 1; i <= 5; i++) { System.out.println(name + "執行了[" + i + "]次"); } }, "線程1"); System.out.println("主線程開始執行!"); thread1.start(); //thread2自旋喚醒阻塞在lock對象上的主線程 Thread thread2 = new Thread(new Thread() { @Override public void run() { while (!thread1.isAlive() && !Thread.currentThread().isInterrupted()) { synchronized (lock) { System.out.println("enter"); lock.notifyAll(); System.out.println("exit"); } } } }, "線程2"); thread2.start(); try { synchronized (lock) { while (thread1.isAlive()) { System.out.println("bb"); lock.wait(); //中止thread2自旋 thread2.interrupt(); System.out.println("tt"); } } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主線程執行結束!"); } }
Output:線程
主線程開始執行! bb 線程1開始執行! 線程1執行了[1]次 線程1執行了[2]次 線程1執行了[3]次 線程1執行了[4]次 線程1執行了[5]次 enter exit enter exit tt 主線程執行結束!
這裏添加了一個線程thread2
用於專門自旋喚醒主線程調試
用於替換案例一中的,thread1
線程結束後,jvm
喚醒主線程操做
Thread類中,join源碼:
//Thread類中 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) { //這個分支是無限期等待直到b線程結束 while (isAlive()) { wait(0); } } else { //這個分支是等待固定時間,若是b沒結束,那麼就不等待了。 while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
join成員方法中有synchronized
,鎖定的對象爲調用該方法的對象,即子線程thread1
,即主線程持有了thread1
對象鎖
能夠本身調試,發現進入到join源碼的線程爲主線程
子線程thread1
執行完畢的時候,jvm
會自動喚醒阻塞在thread1
對象上的線程,在咱們的例子中也就是主線程。至此,thread1
線程對象被notifyall
了,那麼主線程也就能繼續跑下去了
who and when notify the thread.wait() when thread.join() is called?