首页 > 技术文章 > 多线程之join的理解

1023linlin 2019-11-16 10:22 原文

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。

 

推荐阅读