JUC源码讲解:逐步解析 join()

问题抛出

join() 在源码中其实是使用了 wait() 方法的, 因此, wait() 的特性 join() 都能继承过来, 我们知道wait()有什么特性呢?

wait()的特性:

  • 会释放锁
  • 对中断异常敏感
  • 会释放CPU时间片

我也对wait()做了讲解,想了解可移步 https://www.cnblogs.com/acdongla/p/18071381

可是, join() 真的会释放锁吗? 为什么一些例子中, 使用join() 后其他线程仍然被阻塞住了?join() 还有什么需要注意的特性吗? 让我们带着问题寻找答案吧

解析源码

进入 join() 看到这样一段代码

public final void join() throws InterruptedException {
    join(0);
}

深入进去,点开看看:

这里先把源码贴出来,之后会逐步解析

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;
        }
    }
}

先看这段代码:

if (millis < 0) {
    throw new IllegalArgumentException("timeout value is negative");
}

可以看到, 传递的时间不能是负数

一个重点来了, alive() 函数出现了:

if (millis == 0) {
    while (isAlive()) {
        wait(0);
    }

isAlive() 是对线程状态的检查, 必须是start()后的线程才会满足条件.

因此,因为有 isAlive() 的检查 , join()函数只能在线程 start() 后使用

注意!!! 这里的 wait(0)

我们知道, wait()能释放锁资源, 可我们需要注意一个问题, 这里的 wait() 释放的是谁的锁资源?

答: **释放的是当前线程的锁资源, 这里的wait()是 currentThread.wait(), 是 this.wait() **

我们写一段代码来说明这个问题

public class Main {

    @SneakyThrows
    public static void main(String[] args) {
        new Thread(new YYThread(), "YY-1").start();
        Thread.sleep(100);
        new Thread(new YYThread(), "YY-2").start();
    }

    static class YYThread implements Runnable {

        @SneakyThrows
        @Override
        public void run() {
            /// 注意!!! 这里使用锁对象是 Main.class
            synchronized (Main.clsss) {
                System.out.println(Thread.currentThread().getName() + "启动了");

                Thread.currentThread().join();

            }
        }
    }
}

注意, 在sync中使用的锁对象是 Main.class

运行这段代码,会发现线程 “YY-2” 被阻塞了

为什么, join()不是同wait()一样,会释放锁资源吗?

但!!! wait()释放的是当前线程的锁资源, 因此,使用全局变量来作为锁是不可行的

我们把run()函数做这样的修改,就可以不阻塞了

public void run() {
    /// 修改了锁, 修改为了当前线程
    synchronized (Thread.currentThread()) {
        System.out.println(Thread.currentThread().getName() + "启动了");

        Thread.currentThread().join();

    }
}

修改后,从输出上看,两个线程都正常运行了

总结

  • join() 完全继承了 wait() 方法的特性, 但需要注意的事, join() 中的源码使用了wait(), 代表的事 currentThread.wait(), 是”当前线程.wait()”,因此释放的只是当前线程的锁资源
  • 因为源码中对isAlive() 的判断, join() 只能在线程 start() 之后才能使用
  • join() 的参数不能是负数
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。