join() ,与sleep()(不释放锁)、wait()(释放锁)方法都属于多线程运行控制常用方法。
join()的作用类似与排队,比如ThreadA调用了ThreadB的join()方法,则ThreadA会进入阻塞状态,ThreadB会一直运行,知道ThreadB结束后ThreadA才会继续执行。 场景比如,主线程需要等待子线程的运行结果进行汇总,如果主线程先于子线程运行完成,结果就会有误差,所以需要在主线程中调用子线程的join()方法,这样主线程就会等子线程运行完成后才会运行。类似的作用还有countDownLatch,countDownLatch还能灵活一点,能实现更复杂的业务场景。因为join是必须等待子线程运行完成后才会允许主线程执行,而countDownLatch子线程可以在任何阶段主动countDown。
下面举几个例子。
package join; import lombok.extern.slf4j.Slf4j; /** * Description: * * @author: wulei * Version: 1.0 * Create Date Time: 2019/11/16 10:36 AM. * Update Date Time: */ @Slf4j public class ThreadMain { public static void main(String[] args) throws InterruptedException{ log.info("ThreadMain开始执行"); ThreadChild1 threadChild1 = new ThreadChild1(); threadChild1.start(); // 可以把join方法注释后观察结果 threadChild1.join(); log.info("ThreadMain执行完毕"); } }
package join; import lombok.extern.slf4j.Slf4j; /** * Description: * * @author: wulei * Version: 1.0 * Create Date Time: 2019/11/16 10:51 AM. * Update Date Time: */ @Slf4j public class ThreadChild1 extends Thread { @Override public void run(){ int sleepTime = (int)(Math.random() * 1000); try { log.info("ThreadChild1准备执行"); Thread.sleep(sleepTime); log.info("ThreadChild1执行完毕"); } catch (InterruptedException e) { e.printStackTrace(); } } }
join()的源代码如下:
/** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * * <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; } } }
可以看出join()内部是使用wait()方法实现的,也就是说主线程调用了子线程的join()方法后,相当于主线程调用了子线程的wait()方法,主线程调用了子线程的wait方法后就会进入阻塞状态,相当于放弃了cpu的使用权,join(0)相当于forever。