
/** * Waits for this thread to die. *等待当前线程死亡(指的是主线程等待当前线程死亡) * <p> An invocation of this method behaves in exactly the same * way as the invocation * * <blockquote> * {@linkplain #join(long) join}{@code (0)} * </blockquote> * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public final void join() throws InterruptedException { join(0); } /** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. *此线程最多等待指定秒数。假如参数为0,则无限期等待下去,所以无参的join是无限期等待下去(主线程等待),直到调用它的线程(使用对象.join的线程)完成线程里的任务为止。 * * <p> This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ 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()) {//子线程能否还活着 wait(0);//主线程等待 } } else { while (isAlive()) {//子线程能否还活着 long delay = millis - now; if (delay <= 0) { break; } wait(delay);//主线程等待 now = System.currentTimeMillis() - base; } } }从上述代码可以看出,假如传入的参数millis小于0,则抛出异常;假如等于0,则循环判断当前线程能否还活着,假如还活着,则主线程等待(这里wait(0)和wait()是一样的,由于wait()方法里就是调用的wait(0)方法);假如大于0,则循环判断当前线程能否还活着,假如活着,则主线程等待指定秒数。
public final void wait() throws InterruptedException { wait(0);}这里为啥是主线程等待?给大家看个例子就很容易了解了。
public static void main(String[] args) { Thread thread1 = new Thread(new Runnable() { @Override public void run() { // TODO 自动生成的方法存根 } }); thread1.start(); // try {// thread1.join();// } catch (InterruptedException e) {// // TODO 自动生成的 catch 块// e.printStackTrace();// } synchronized(thread1){ ... while (isAlive()) { wait(0); } ... } } 上述代码thread1.join()代码其实就是synchronized(thread1)而后执行接下来的内容,所以wait对象是主线程,而不是thread1。
join方法是让主线程(父线程)等待子线程里面的内容执行完毕并死亡后再执行主线程里的内容,在子线程执行的时候,主线程(父线程)阻塞。
SonThread方法
package com.yds.test;public class SonThread extends Thread { @Override public void run() { for(int i=0;i<4;i++){ try { Thread.sleep(1000); System.out.println("子线程:"+i); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }}Test调用
package com.yds.test;public class Test { public static void main(String[] args) { try { System.out.println("主线程运行:"); SonThread son = new SonThread(); son.start(); System.out.println("主线程阻塞并等待子线程执行完:"); son.join(); System.out.println("子线程执行完毕,主线程开始执行"); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } }}执行结果:
主线程运行:主线程阻塞并等待子线程执行完:子线程:0子线程:1子线程:2子线程:3子线程执行完毕,主线程开始执行join方法在哪个线程运行,则会阻塞哪个线程,直到调用它的线程(指的是通过对象.join方式调用的线程,如thread1.join,这个调用它的线程就是指thread1)执行完毕并死亡,主线程才会继续运行。