Object类join()方法解析

join方法通常用来做同步操作,如果线程1在线程2之后执行,就可以在线程1中调用线程2.join()方法来实现。实际上这个操作我们用wait/notify也是可以实现的。

@Slf4j
public class Demo {
    private static Demo lock = new Demo();

    public static void main(String[] args) throws Throwable {
        new Thread(() -> {
            synchronized (lock) {
                try {
                    log.info("我是线程1,我需要先执行");
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lock.notifyAll();
            }
        }).start();

        synchronized (lock) {
            lock.wait();
        }

        log.info("我是线程2,我需要在线程1之后执行");
    }
}

结果

09:25:55.705 com.ailik.d1.wait_notify.Demo [Thread-0] - 我是线程1,我需要先执行
09:25:57.709 com.ailik.d1.wait_notify.Demo [main] - 我是线程2,我需要在线程1之后执行

进程已结束,退出代码为 0

接下来使用join方法实现

@Slf4j
public class Demo {
    @SneakyThrows
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                log.info("我是线程1,我需要先执行");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();

        t1.join();

        log.info("我是线程2,我需要在线程1之后执行");
    }
}

实际上join()方法内部同样是wait/notify的操作。接下来我们来看一下join()的源码(这里只贴重要部分)

public final synchronized void join(long millis)
    while (isAlive()) {
        wait(0);
    }    
}

从源码中我们可以得到的以下信息

1、这是一个同步方法(同步锁是线程对象,也就是线程2的线程对象)
2、里面调用了wait方法,wait方法作用是使当前线程进入锁对象的等待池(注意:当前线程是线程1。因为代码是在线程1中调用的join方法)

线程1调用join方法后,会被wait方法阻塞,但是似乎并没有一个可以唤醒线程1的notify方法。但是从效果来看,这个notify方法应该是存在的。之后我又通过查询资料,最后去翻看jdk源码发现确实线程结束之后调用了notifyAll方法(这里也是只贴关键方法)

void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
  ensure_join(this);
}

static void ensure_join(JavaThread* thread) {
  lock.notify_all(thread);
}

那么就结案了
线程1调用线程2.join()方法后会被阻塞,同步锁是线程2对象。当线程2执行完后又会调用notifyAll来唤醒线程2等待池中的所有线程对象


 


版权声明:本文为qq_59116252原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。