zoukankan      html  css  js  c++  java
  • 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】边叫边练。

     

     

  • 相关阅读:
    【iOS CocoaPods篇】iOS CocoaPods一些特别的用法 指定版本、版本介绍、忽略警告
    【iOS CocoaPods篇】iOS 10.10 10.11 10.12 安装升级CocoPods
    iOS程序中的内存分配 栈区堆区全局区(转)
    retain和strong、assign和weak的区别(转)
    (ios实战):retain,copy,assign及autorelease ,strong,weak(转)
    malloc()与 alloc()区别 (转)
    iOS开发--KVC&KVO
    iOS开发之支付功能概述(转)
    disptch_after 自递归
    makeObjectsPerformSelector 方法的用法
  • 原文地址:https://www.cnblogs.com/jiaolian/p/14460995.html
Copyright © 2011-2022 走看看