写点什么

join 为啥会阻塞主线程?

用户头像
叫练
关注
发布于: 2021 年 02 月 28 日
join为啥会阻塞主线程?

join 使用


上篇我们介绍了 CountDownLatch,顺便说到了 Thread 中的 join 方法!

import java.util.concurrent.TimeUnit;
/** * @author :jiaolian * @date :Created in 2021-02-28 21:43 * @description:join测试 * @modified By: * 公众号:叫练 */public class JoinTest {
public static void main(String[] args) throws InterruptedException { Thread threadA = new Thread(()->{ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":想先执行"); },"线程A"); //开启一个线程A threadA.start(); //主线程会持有子线程的锁,子线程还没开始主线程就阻塞了,等待子线程结束后通知; threadA.join(); System.out.println(Thread.currentThread().getName()+ "线程执行"); }}
复制代码

如上代码所示:在 JoinTest 开启一个线程 A,threadA 调用 join()方法,主线程会等待 threadA 执行完毕!也就是两秒后,主线程执行最后一句话,运行结果如下图所示!


image.png


我们深入源码,join 方法底层其实就是一个 wait 方法,但现在问题是:明明调用者是线程 A,可阻塞的是 mian 线程,不应该阻塞的是 threadA 吗?


证明问题:明明调用者是线程 A,可阻塞的是 mian 线程


我们参照 Thread 中 join 源码,将上面的代码改造如下:

import java.util.concurrent.TimeUnit;
/** * @author :jiaolian * @date :Created in 2021-02-28 21:43 * @description:join测试 * @modified By: * 公众号:叫练 */public class JoinCodeTest {
public static void main(String[] args) throws InterruptedException {
MyThread threadA = new MyThread("线程A"); //开启一个线程A threadA.start(); //主线程会持有子线程的锁,子线程还没开始主线程就阻塞了,等待子线程结束后通知; threadA.join2(0); System.out.println(Thread.currentThread().getName()+ "线程执行"); }
private static class MyThread extends Thread {
public MyThread(String name) { super(name); }
@Override public void run() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":想先执行"); }
//复制Thread源码中的join方法测试阻塞的是线程A还是main线程? public final synchronized void join2(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()) { //虽然调用者是线程A,但真正执行阻塞的是main线程! System.out.println(Thread.currentThread().getName()+"会阻塞"); wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } } }}
复制代码

如上代码所示:MyThread 继承 Thread,并复制了 join 源码,将 join 修改成 join2,并在 join2 方法中增加了一个输出语句,System.out.println(Thread.currentThread().getName()+"会阻塞")用来测试阻塞的是线程 A 还是 main 线程,所以在 JoinCodeTest 的 main 方法中 ThreadA 是调用 join2 方法,

结果发现进入 join2 方法的线程是 main 线程。运行结果如下图所示!


image.png


这里可以把 join 理解成一个普通方法!真正阻塞的不是调用者线程,而是当前正在执行的线程。


总结


今天我们介绍了 join 方法,特别是将源码中代码 copy 出来证明测试,相信整理出来希望能对你有帮助,写的比不全,同时还有许多需要修正的地方,希望亲们加以指正和点评,喜欢的请点赞加关注哦。点关注,不迷路,我是叫练公众号,微信号【jiaolian123abc】边叫边练。


发布于: 2021 年 02 月 28 日阅读数: 11
用户头像

叫练

关注

我是叫练,边叫边练 2020.06.11 加入

Java高级工程师,熟悉多线程,JVM

评论

发布
暂无评论
join为啥会阻塞主线程?