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?