摘要:當(dāng)時(shí),會(huì)進(jìn)入循環(huán),系統(tǒng)會(huì)判斷主線程是否處于活躍狀態(tài),如果處于活躍狀態(tài),主線程就會(huì)不停的等待。
介紹由于前段時(shí)間比較忙,線程這快學(xué)習(xí)停滯了,只能利用周日的時(shí)間來(lái)寫(xiě)寫(xiě)博客了,多線程Join方法的作用就是把指定的線程加入到當(dāng)前線程,讓主線程等待子線程結(jié)束之后才能繼續(xù)運(yùn)行,從而完成同步操作
join() 的作用:讓主線程等待子線程結(jié)束之后才能繼續(xù)運(yùn)行,首先先來(lái)看下以采集為案例的代碼,統(tǒng)計(jì)采集所消耗的時(shí)長(zhǎng)
需求:當(dāng)所有線程任務(wù)執(zhí)行完畢,統(tǒng)計(jì)最終消耗時(shí)長(zhǎng)
public class ThreadJoin { public static void main(String[] args) throws InterruptedException { long startTime = System.currentTimeMillis(); Thread t1 = new Thread(new CaptureRunnable("M1", 5_000L)); Thread t2 = new Thread(new CaptureRunnable("M2", 3_000L)); Thread t3 = new Thread(new CaptureRunnable("M3", 2_000L)); t1.start(); t2.start(); t3.start(); System.out.println("采集完成,消耗 " + (System.currentTimeMillis() - startTime)); } } class CaptureRunnable implements Runnable { private String machineName;//采集任務(wù)名 private Long spendTime;//采集工作消耗時(shí)長(zhǎng) public CaptureRunnable(String machineName, Long spendTime) { this.machineName = machineName; this.spendTime = spendTime; } @Override public void run() { try { System.out.println(machineName + "開(kāi)始采集"); Thread.sleep(spendTime); } catch (InterruptedException e) { e.printStackTrace(); } } }
在ThreadJoin的代碼中,我們創(chuàng)建了主線程main,和實(shí)現(xiàn)了Runnable的CaptureRunnable子線程,運(yùn)行main方法,可以看到在未使用join()的情況下,統(tǒng)計(jì)結(jié)果并不理想,正確輸出應(yīng)該是5000毫秒以上
采集完成,消耗 1 M1開(kāi)始采集 M2開(kāi)始采集 M3開(kāi)始采集使用join
在start方法下添加join操作,運(yùn)行main方法,發(fā)現(xiàn)不管那個(gè)線程先執(zhí)行,結(jié)果都是5000毫秒以上,因?yàn)橹骶€程main接收到了M1,M2,M3三個(gè)線程的join指令,這個(gè)時(shí)候主線程則會(huì)處于阻塞狀態(tài),直到子線程執(zhí)行完畢后才會(huì)繼續(xù)執(zhí)行下去...
t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); t3.join();
M2開(kāi)始采集 M1開(kāi)始采集 M3開(kāi)始采集 采集完成,消耗 5001部分join
去掉M1線程調(diào)用的join,然后運(yùn)行main方法,從日志輸出中可以發(fā)現(xiàn),main會(huì)等待M2,M3執(zhí)行完畢后才會(huì)繼續(xù)執(zhí)行下去
M1開(kāi)始采集 M3開(kāi)始采集 M2開(kāi)始采集 采集完成,消耗 3001源碼分析
public final void join() throws InterruptedException { join(0); } public final synchronized void join(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()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
說(shuō)明
從代碼中,我們可以發(fā)現(xiàn)。當(dāng)millis==0時(shí),會(huì)進(jìn)入while(isAlive())循環(huán),系統(tǒng)會(huì)判斷主線程是否處于活躍狀態(tài),如果處于活躍狀態(tài),主線程就會(huì)不停的等待。
問(wèn)題
為什么子線程調(diào)用join()阻塞的卻是主線程呢?join()方法中的isAlive()應(yīng)該是判斷子線程是否處于活躍的狀態(tài),對(duì)應(yīng)的wait(0)也應(yīng)該是讓子線程等待才對(duì)
答案
首先從源碼中我們可以發(fā)現(xiàn)它是被synchronized修飾的方法,當(dāng)前線程的對(duì)象調(diào)用join后,其實(shí)獲取到了子線程M1,M2,M3的鎖,當(dāng)子線程鎖釋放后才會(huì)繼續(xù)執(zhí)行主線程的操作
使用jvisualvm分析器,可以發(fā)現(xiàn)Thread-1-3與主線程main,處于等待的是主線程,子線程因?yàn)檎{(diào)用了sleep處于休眠狀態(tài)(為了演示耗時(shí)操作)
- 說(shuō)點(diǎn)什么全文代碼:https://git.oschina.net/battcn/battcn-concurent/tree/master/Chapter1-1/battcn-thread/src/main/java/com/battcn/chapter3
個(gè)人QQ:1837307557
battcn開(kāi)源群(適合新手):391619659
微信公眾號(hào):battcn(歡迎調(diào)戲)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67631.html
摘要:文本將介紹兩種可以優(yōu)雅的終止線程的方式第一種在多線程模式中有一種叫兩步終止的模式可以優(yōu)雅的終止線程,這種模式采用了兩個(gè)步驟來(lái)終止線程,所以叫兩步終止模式。 Java中原來(lái)在Thread中提供了stop()方法來(lái)終止線程,但這個(gè)方法是不安全的,所以一般不建議使用。文本將介紹兩種可以優(yōu)雅的終止線程的方式... 第一種 在JAVA《Java多線程模式》中有一種叫Two-Phase Term...
摘要:在之前,不能為線程單獨(dú)設(shè)置或指定一個(gè)默認(rèn)的,為了設(shè)置,需要繼承并覆寫(xiě)方法。幸運(yùn)的是后線程提供了一個(gè)方法,用來(lái)捕獲并處理因線程中拋出的未知異常,以避免程序終止。 在單線程的開(kāi)發(fā)過(guò)程中,通常采用try-catch的方式進(jìn)行異常捕獲,但是這種方式在多線程環(huán)境中會(huì)顯得無(wú)能為力,而且還有可能導(dǎo)致一些問(wèn)題的出現(xiàn),比如發(fā)生異常的時(shí)候不能及時(shí)回收系統(tǒng)資源,或者無(wú)法及時(shí)關(guān)閉當(dāng)前的連接... 概述 Ja...
摘要:定義等待該線程終止,比如線程調(diào)用了線程的,那么線程要等到線程執(zhí)行完后,才可以繼續(xù)執(zhí)行。 定義 等待該線程終止,比如A線程調(diào)用了B線程的join,那么A線程要等到B線程執(zhí)行完后,才可以繼續(xù)執(zhí)行。 示例 public class JoinDemo { static class JoinThread1 implements Runnable { Thread thre...
摘要:思想把大任務(wù)分割成多個(gè)小任務(wù),再把小任務(wù)的結(jié)果匯總,最終得到大任務(wù)的結(jié)果。當(dāng)一個(gè)線程執(zhí)行完當(dāng)前隊(duì)列的任務(wù)時(shí),他就會(huì)去竊取其他隊(duì)列的任務(wù)來(lái)執(zhí)行。當(dāng)雙端隊(duì)列只有一個(gè)任務(wù)時(shí),線程之間會(huì)競(jìng)爭(zhēng)。 思想 把大任務(wù)分割成多個(gè)小任務(wù),再把小任務(wù)的結(jié)果匯總,最終得到大任務(wù)的結(jié)果。 步驟如下: 任務(wù)分割 結(jié)果匯總 示例圖 showImg(https://segmentfault.com/img/bVb...
摘要:上一章介紹過(guò)關(guān)鍵字,使用它可以給程序互斥部分加上一把鎖從而達(dá)到同步的效果,但錯(cuò)誤的用法會(huì)導(dǎo)致多個(gè)線程同時(shí)被阻塞死鎖死鎖多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或者全部都在等待某個(gè)資源被釋放。由于線程被無(wú)限期地阻塞,因此程序不可能正常終止。 上一章介紹過(guò)synchronized關(guān)鍵字,使用它可以給程序互斥部分加上一把鎖從而達(dá)到同步的效果,但錯(cuò)誤的用法會(huì)導(dǎo)致多個(gè)線程同時(shí)被阻塞.... 死鎖 死鎖...
閱讀 1689·2021-11-15 11:37
閱讀 3422·2021-09-28 09:44
閱讀 1662·2021-09-07 10:15
閱讀 2799·2021-09-03 10:39
閱讀 2697·2019-08-29 13:20
閱讀 1304·2019-08-29 12:51
閱讀 2214·2019-08-26 13:44
閱讀 2131·2019-08-23 18:02