乐趣区

关于面试: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 执行结束!也就是两秒后,主线程执行最初一句话,运行后果如下图所示!

咱们深刻源码,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 线程。运行后果如下图所示!

这里能够把 join 了解成一个一般办法!真正阻塞的不是调用者线程,而是以后正在执行的线程。

总结


明天咱们介绍了 join 办法,特地是将源码中代码 copy 进去证实测试,置信整理出来心愿能对你有帮忙,写的比不全,同时还有许多须要修改的中央,心愿亲们加以斧正和点评,喜爱的请点赞加关注哦。 点关注,不迷路,我是【叫练 公众号 ,微信号【jiaolian123abc】 边叫边练。

退出移动版