join方法 详解

@ 先看一个案例:小明和妈妈准备做饭,小明呢,负责买菜,妈妈负责做饭,做饭的前提呢是要等小明买完菜回来才能做饭,想一想如何实现呢?

​ 以往常方式,我们是这样写的:

// 省略了try catch 捕获
new Thread(() -> {
    Thread.sleep(6_000);
    System.out.println("买完菜回来了!");
}, "小明").start();

new Thread(() -> {
	Thread.sleep(5_000);
	System.out.println("饭已做好!");
}, "妈妈").start();
复制代码

​ 实际结果却是:
image-20210707120012801.png

​ 菜没买回来,饭却做好了,这是怎么回事呢,哦,原来是我们的程序是异步执行的,小明跟妈妈之间 ​ 没任何的关联,各执行各的,所以就造成了上面的错误。

​ 那该如何解决呢,请看下面的解释……


我们要让小明执行完,妈妈才能执行,这里的过程称为同步,那么实现同步,方法就有很多了,但是这里我们不一一解释,我们使用 join 来实现此功能……

Thread xiaoMing = new Thread(() -> {
    try {
        Thread.sleep(4_000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("买完菜回来了!");
}, "小明");

xiaoMing.start();
xiaoMing.join();

try {
    Thread.sleep(3_000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("妈妈饭已做好!");
复制代码

运行结果:

image-20210707152945831.png

原理

join() 方法有两个重载方法,

1:join(long millis) –> 表示在 millis 毫秒之后如果还没执行完,则主线程可以执行了。

2:join(long millis, int nanos) –> 表示在 millis 毫秒 + nanos纳秒 之后如果还没执行完,则主线程可以执行了。

注:如果不传参数,默认参数为 0


join 源码

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) { // 此处判断当 join 的参数为0时,会调用 wait 方法进行无期限等待
        while (isAlive()) {
            wait(0);
        }
    } else { // 如果传递了参数,则不会无限期等待
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}
复制代码

总结:首先 join() 是一个 synchronized 方法, 里面调用了 wait(),这个过程的目的是让持有这个同步锁的线程进入等待,那么谁持有了这个同步锁呢?答案是主线程,因为主线程调用了threadA.join() 方法,相当于在 threadA.join() 代码这块写了一个同步代码块,谁去执行了这段代码呢,是主线程,所以主线程被wait()了。然后在子线程threadA执行完毕之后,JVM会调用lock.notify_all(thread);唤醒持有threadA这个对象锁的线程,也就是主线程,会继续执行。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享