Java線程Thread.join方法解析

join字面上是加入的意思,我們先看看join方法的解釋和實(shí)現(xiàn)庶喜。

/**
     * Waits for this thread to die.
     * 調(diào)用方線程(調(diào)用join方法的線程)執(zhí)行等待操作,直到被調(diào)用的線程(join方法所屬的線程)結(jié)束,再被喚醒
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }

這里join是調(diào)用的

/**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     * 等待線程執(zhí)行結(jié)束索赏,或者指定的最大等待時(shí)間到了,調(diào)用方線程再次被喚醒贴彼,如果最大等待時(shí)間為0潜腻,則只能等線程執(zhí)行結(jié)束,才能被喚醒器仗。
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * 
     */
    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;
            }
        }
    }

可以看到融涣,join方法本身是通過(guò)wait方法來(lái)實(shí)現(xiàn)等待的童番,這里判斷如果線程還在運(yùn)行中的話,則繼續(xù)等待威鹿,如果指定時(shí)間到了剃斧,或者線程運(yùn)行完成了,則代碼繼續(xù)向下執(zhí)行忽你,調(diào)用線程就可以執(zhí)行后面的邏輯了幼东。
但是在這里沒(méi)有看到哪里調(diào)用notify或者notifyAll方法,如果沒(méi)有調(diào)用的話檀夹,那調(diào)用方線程會(huì)一直等待下去筋粗,那是哪里調(diào)用了喚醒它的方法呢?通過(guò)查證得知炸渡,原來(lái)在線程結(jié)束時(shí)娜亿,java虛擬機(jī)會(huì)執(zhí)行該線程的本地exit方法,

//線程退出函數(shù):
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
...
//這里會(huì)處理join相關(guān)的銷毀邏輯
ensure_join(this);
...
}
//處理join相關(guān)的銷毀邏輯
    static void ensure_join(JavaThread* thread) {
      Handle threadObj(thread, thread->threadObj());

      ObjectLocker lock(threadObj, thread);

      thread->clear_pending_exception();

      java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);

      java_lang_Thread::set_thread(threadObj(), NULL);

      //這里就調(diào)用notifyAll方法蚌堵,喚醒等待的線程
      lock.notify_all(thread);

      thread->clear_pending_exception();
    }

這樣線程什么時(shí)候被喚醒就明白了买决。下面寫個(gè)例子看下效果。

public class JoinTest {
    
    public static void main(String[] args) {
        
        ThreadBoy boy = new ThreadBoy();
        boy.start();
        
    }
    
    static class ThreadBoy extends Thread{
        @Override
        public void run() {
            
            System.out.println("男孩和女孩準(zhǔn)備出去逛街");
            
            ThreadGirl girl = new ThreadGirl();
            girl.start();
            
            try {
                girl.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println("男孩和女孩開始去逛街了");
        }
    }
    
    static class ThreadGirl extends Thread{
        @Override
        public void run() {
            int time = 5000;
            
            System.out.println("女孩開始化妝,男孩在等待吼畏。督赤。。");
            
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println("女孩化妝完成泻蚊!躲舌,耗時(shí)" + time);
            
        }
    }
    
}

執(zhí)行結(jié)果為:
男孩和女孩準(zhǔn)備出去逛街
女孩開始化妝,男孩在等待。性雄。没卸。
女孩化妝完成!秒旋,耗時(shí)5000
男孩和女孩開始去逛街了

就是男孩和女孩準(zhǔn)備去逛街约计,女孩要化妝先,等女孩化妝完成了迁筛,再一起去逛街煤蚌。

那join(time)的用法是怎么樣的呢?

public class JoinTest {
    
    public static void main(String[] args) {
        
        ThreadBoy boy = new ThreadBoy();
        boy.start();
        
    }
    
    static class ThreadBoy extends Thread{
        @Override
        public void run() {
            
            System.out.println("男孩和女孩準(zhǔn)備出去逛街");
            
            ThreadGirl girl = new ThreadGirl();
            girl.start();
            
            int time = 2000;
            try {
                girl.join(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println("男孩等了" + time + ", 不想再等了细卧,去逛街了");
        }
    }
    
    static class ThreadGirl extends Thread{
        @Override
        public void run() {
            int time = 5000;
            
            System.out.println("女孩開始化妝,男孩在等待尉桩。。贪庙。");
            
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println("女孩化妝完成蜘犁!,耗時(shí)" + time);
            
        }
    }
    
}

這里僅僅把join方法換成了join(time)方法插勤,描述改了點(diǎn)沽瘦,打印的結(jié)果是:
男孩和女孩準(zhǔn)備出去逛街
女孩開始化妝,男孩在等待革骨。。析恋。
男孩等了2000, 不想再等了良哲,去逛街了
女孩化妝完成!助隧,耗時(shí)5000

男孩等了join(time)中的time時(shí)間筑凫,如果這個(gè)time時(shí)間到達(dá)之后,女孩所在的線程還沒(méi)執(zhí)行完并村,則不等待了巍实,繼續(xù)執(zhí)行后面的邏輯,就是不等女孩了哩牍,自己去逛街棚潦。

由此看出,join方法是為了比較方便的實(shí)現(xiàn)兩個(gè)線程的同步執(zhí)行膝昆,線程1執(zhí)行丸边,碰到線程2后,等待線程2執(zhí)行后荚孵,再繼續(xù)執(zhí)行線程1的執(zhí)行妹窖,加入的意思現(xiàn)在就比較形象化了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末收叶,一起剝皮案震驚了整個(gè)濱河市骄呼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌判没,老刑警劉巖蜓萄,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異哆致,居然都是意外死亡绕德,警方通過(guò)查閱死者的電腦和手機(jī)患膛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門摊阀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人踪蹬,你說(shuō)我怎么就攤上這事胞此。” “怎么了跃捣?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵漱牵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我疚漆,道長(zhǎng)酣胀,這世上最難降的妖魔是什么刁赦? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮闻镶,結(jié)果婚禮上甚脉,老公的妹妹穿的比我還像新娘。我一直安慰自己铆农,他們只是感情好牺氨,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墩剖,像睡著了一般猴凹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上岭皂,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天郊霎,我揣著相機(jī)與錄音,去河邊找鬼爷绘。 笑死歹篓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的揉阎。 我是一名探鬼主播庄撮,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼毙籽!你這毒婦竟也來(lái)了洞斯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坑赡,失蹤者是張志新(化名)和其女友劉穎烙如,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毅否,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亚铁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了螟加。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徘溢。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖捆探,靈堂內(nèi)的尸體忽然破棺而出然爆,到底是詐尸還是另有隱情,我是刑警寧澤黍图,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布曾雕,位于F島的核電站,受9級(jí)特大地震影響助被,放射性物質(zhì)發(fā)生泄漏剖张。R本人自食惡果不足惜切诀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搔弄。 院中可真熱鬧趾牧,春花似錦、人聲如沸肯污。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹦渣。三九已至哄芜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柬唯,已是汗流浹背认臊。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锄奢,地道東北人失晴。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拘央,于是被迫代替她去往敵國(guó)和親涂屁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,949評(píng)論 1 18
  • 本文主要講了java中多線程的使用方法灰伟、線程同步拆又、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法栏账、概述等帖族。 首先講...
    李欣陽(yáng)閱讀 2,439評(píng)論 1 15
  • 下面是我自己收集整理的Java線程相關(guān)的面試題,可以用它來(lái)好好準(zhǔn)備面試挡爵。 參考文檔:-《Java核心技術(shù) 卷一》-...
    阿呆變Geek閱讀 14,735評(píng)論 14 507
  • 你看不清楚自己的來(lái)路 我卻看見你細(xì)碎的步伐和盈盈的眼波竖般,透露著歡喜 你從前生那么遠(yuǎn)向我走來(lái) 舊時(shí)光的氣息攜裹著零星...
    Kola說(shuō)閱讀 334評(píng)論 0 10
  • 我閉著眼昏昏沉沉的時(shí)候,樓下的聲音格外清楚茶鹃,籃球撞擊地面和籃筐的“砰砰”聲涣雕、男生的吼叫聲和女生的尖叫聲、遠(yuǎn)處除草機(jī)...
    亟安閱讀 177評(píng)論 0 0