join爲啥會阻塞主線程?

join使用


上篇咱們介紹了CountDownLatch,順便說到了Thread中的join方法!java

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嗎?ide


證實問題:明明調用者是線程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方法,spa

結果發現進入join2方法的線程是main線程。運行結果以下圖所示!線程

image.png

這裏能夠把join理解成一個普通方法!真正阻塞的不是調用者線程,而是當前正在執行的線程。blog


總結


今天咱們介紹了join方法,特別是將源碼中代碼copy出來證實測試,相信整理出來但願能對你有幫助,寫的比不全,同時還有許多須要修正的地方,但願親們加以指正和點評,喜歡的請點贊加關注哦。點關注,不迷路,我是叫練公衆號,微信號【jiaolian123abc】邊叫邊練。繼承

相關文章
相關標籤/搜索