爲何會忽然想到這麼一個方法,好像你們工做中不怎麼經常使用,可是在平時的面試中只要涉及到多線程中,大多狀況下都會問到這個方法,咱們也只是簡單的看看面試題說個大概,可是真正的用法你們可能跟我以前同樣是比較模糊的。前端
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()的代碼,首先開啓線程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()的位置不能亂寫,咱們來看兩端代碼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,因此此時的多線程代碼,其實已經變成了單線程,咱們來看下兩段代碼的執行結果。
第一段代碼結果:
第二段代碼結果:
很明顯,第一段代碼纔是咱們想要的多線程結果。
歡迎你們一塊兒交流!!!