多線程中的join()方法,你真的瞭解嗎?

爲何會忽然想到這麼一個方法,好像你們工做中不怎麼經常使用,可是在平時的面試中只要涉及到多線程中,大多狀況下都會問到這個方法,咱們也只是簡單的看看面試題說個大概,可是真正的用法你們可能跟我以前同樣是比較模糊的。前端

一、先看一段代碼,你以爲下面的代碼的輸出順序是什麼?

public static void main(String[] args) throws Exception {        Thread t1 = new Thread(() -> {            try {                Thread.sleep(3000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("線程A執行");        });        Thread t2 = new Thread(() -> {            try {                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("線程B執行");        });        t1.start();        t2.start();        System.out.println("我是主線程");    }複製代碼

沒錯,執行結果確實是大部分人猜想的那樣,先是主線程執行,而後線程B執行,最後是線程A。面試

咱們來稍微改一下代碼bash

public static void main(String[] args) throws Exception {        Thread t1 = new Thread(() -> {            try {                Thread.sleep(3000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("線程A執行");        });        Thread t2 = new Thread(() -> {            try {                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("線程B執行");        });        t1.start();        t1.join();        t2.start();        System.out.println("我是主線程");    }複製代碼

大家來以爲執行順序會是什麼?咱們先來看下答案吧!帶着問題咱們來認識join方法,到底幹了什麼。多線程


二、join()方法

大白話:就是誰調用這個方法,就讓調用此方法的線程進入阻塞狀態,等待我執行完畢以後,再往下執行;網站

那麼咱們再來看上面那段加了join()的代碼,首先開啓線程A,緊接着線程A調用了join()方法進入阻塞狀態,那麼線程必須等待線程A執行結束以後再往下執行,線程A執行完畢,線程B開啓,進入睡眠,主線程執行,線程B睡眠結束,執行;spa

三、真實場景需求

我上週在作一個爬蟲項目,大概是這樣的,我要開啓多條線程同時爬取不一樣網站的信息,進行處理,而後統一返回給前臺,這裏面要注意的就是,咱們必須等待前面的線程都執行結束,才能返回給前端,那麼join()方法就很適合咱們的需求。線程

public static void main(String[] args) throws Exception {        Thread t1 = new Thread(() -> {            for (int i = 1; i < 4; i++) {                System.out.println("線程A : " + i);            }        });        Thread t2 = new Thread(() -> {            for (int i = 1; i < 4; i++) {                System.out.println("線程B : " + i);            }        });        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println("爬取結束");    }複製代碼

經過這樣,咱們A、B兩條線程開啓以後開始執行,等待他們所有執行結束以後,再對結果進行統一處理。若是不適用join()方法咱們看看,會是什麼狀況。3d

還沒等線程執行結束,就已經將結果返回回去了,這樣明顯不知足咱們的需求。code

三、注意,join()的位置可不是亂寫的

爲何說join()的位置不能亂寫,咱們來看兩端代碼orm

public static void main(String[] args) throws Exception {        Thread t1 = new Thread(() -> {            for (int i = 1; i < 4; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("線程A : " + i);            }        });        Thread t2 = new Thread(() -> {            for (int i = 1; i < 4; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("線程B : " + i);            }        });        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println("爬取結束");    }複製代碼

public static void main(String[] args) throws Exception {        Thread t1 = new Thread(() -> {            for (int i = 1; i < 4; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("線程A : " + i);            }        });        Thread t2 = new Thread(() -> {            for (int i = 1; i < 4; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("線程B : " + i);            }        });        t1.start();        t1.join();        t2.start();        t2.join();        System.out.println("爬取結束");    }複製代碼

雖然只是將t1.join()的位置變了一下,可是影響是很是大的,改了位置以後這段代碼就變成了了這個意思,t1線程開啓,緊接着t1調用了join()方法,那麼就必須等待t1執行完畢以後再執行t2,因此此時的多線程代碼,其實已經變成了單線程,咱們來看下兩段代碼的執行結果。

第一段代碼結果:


第二段代碼結果:

很明顯,第一段代碼纔是咱們想要的多線程結果。

歡迎你們一塊兒交流!!!

相關文章
相關標籤/搜索