亚洲免费在线视频-亚洲啊v-久久免费精品视频-国产精品va-看片地址-成人在线视频网

您的位置:首頁技術(shù)文章
文章詳情頁

Java中Thread.join()的使用方法

瀏覽:2日期:2022-08-27 16:58:16

概要

本文分三個(gè)部分對(duì)Thread.join()進(jìn)行分析:

1. join() 的示例和作用

2. join() 源碼分析

3. 對(duì)網(wǎng)上其他分析 join() 的文章提出疑問

1. join() 的示例和作用

1.1 示例

// 父線程public class Parent { public static void main(String[] args) { // 創(chuàng)建child對(duì)象,此時(shí)child表示的線程處于NEW狀態(tài) Child child = new Child(); // child表示的線程轉(zhuǎn)換為RUNNABLE狀態(tài) child.start(); // 等待child線程運(yùn)行完再繼續(xù)運(yùn)行 child.join(); }}

// 子線程public class Child extends Thread { public void run() { // ... }}

上面代碼展示了兩個(gè)類:Parent(父線程類),Child(子線程類)。

Parent.main()方法是程序的入口,通過Child child = new Child(); 新建child子線程(此時(shí) child子線程處于NEW狀態(tài));

然后調(diào)用child.start()(child子線程狀態(tài)轉(zhuǎn)換為RUNNABLE);

再調(diào)用child.join(),此時(shí),Parent父線程會(huì)等待child子線程運(yùn)行完再繼續(xù)運(yùn)行。

下圖是我總結(jié)的 Java 線程狀態(tài)轉(zhuǎn)換圖:

Java中Thread.join()的使用方法

1.2 join() 的作用

讓父線程等待子線程結(jié)束之后才能繼續(xù)運(yùn)行。

我們來看看在 Java 7 Concurrency Cookbook 中相關(guān)的描述(很清楚地說明了 join() 的作用):

Waiting for the finalization of a thread

In some situations, we will have to wait for the finalization of a thread. For example, we mayhave a program that will begin initializing the resources it needs before proceeding with therest of the execution. We can run the initialization tasks as threads and wait for its finalizationbefore continuing with the rest of the program.For this purpose, we can use the join() method of the Thread class. When we call thismethod using a thread object, it suspends the execution of the calling thread until the objectcalled finishes its execution.

當(dāng)我們調(diào)用某個(gè)線程的這個(gè)方法時(shí),這個(gè)方法會(huì)掛起調(diào)用線程,直到被調(diào)用線程結(jié)束執(zhí)行,調(diào)用線程才會(huì)繼續(xù)執(zhí)行。

2. join() 源碼分析

以下是 JDK 8 中 join() 的源碼:

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; } }}public final synchronized void join(long millis, int nanos)throws InterruptedException { if (millis < 0) { throw new IllegalArgumentException('timeout value is negative'); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( 'nanosecond timeout value out of range'); } if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; } join(millis);}

join() 一共有三個(gè)重載版本,分別是無參、一個(gè)參數(shù)、兩個(gè)參數(shù):

public final void join() throws InterruptedException;public final synchronized void join(long millis) throws InterruptedException;public final synchronized void join(long millis, int nanos) throws InterruptedException;

其中

(1)三個(gè)方法都被final修飾,無法被子類重寫。

(2)join(long),join(long, long) 是synchronized method,同步的對(duì)象是當(dāng)前線程實(shí)例。

(2)無參版本和兩個(gè)參數(shù)版本最終都調(diào)用了一個(gè)參數(shù)的版本。

(3) join() 和 join(0) 是等價(jià)的,表示一直等下去;join(非0)表示等待一段時(shí)間。

從源碼可以看到 join(0)調(diào)用了Object.wait(0),其中Object.wait(0)會(huì)一直等待,直到被notify/中斷才返回。

while(isAlive())是為了防止子線程偽喚醒(spurious wakeup),只要子線程沒有TERMINATED的,父線程就需要繼續(xù)等下去。

(4) join() 和 sleep() 一樣,可以被中斷(被中斷時(shí),會(huì)拋出 InterrupptedException 異常);不同的是,join() 內(nèi)部調(diào)用了 wait(),會(huì)出讓鎖,而 sleep() 會(huì)一直保持鎖。

以本文開頭的代碼為例,我們分析一下代碼邏輯:

調(diào)用鏈:Parent.main() -> child.join() -> child.join(0) -> child.wait(0)(此時(shí) Parent線程會(huì)獲得 child 實(shí)例作為鎖,其他線程可以進(jìn)入 child.join() ,但不可以進(jìn)入 child.join(0), 因?yàn)閏hild.join(0)是同步方法)。

如果 child 線程是 Active,則調(diào)用 child.wait(0)(為了防止子線程 spurious wakeup, 需要將 wait(0) 放入while(isAlive())循環(huán)中。

一旦 child 線程不為 Active (狀態(tài)為 TERMINATED),child.notifyAll()會(huì)被調(diào)用-> child.wait(0)返回 -> child.join(0)返回 -> child.join()返回 -> Parent.main()繼續(xù)執(zhí)行, 子線程會(huì)調(diào)用this.notify(),child.wait(0)會(huì)返回到child.join(0) ,child.join(0)會(huì)返回到 child.join(), child.join() 會(huì)返回到 Parent 父線程,Parent 父線程就可以繼續(xù)運(yùn)行下去了。

3. 對(duì)網(wǎng)上其他分析 join() 的文章提出疑問

我覺得網(wǎng)上很多文章的描述有歧義,下面挑選一些描述進(jìn)行分析,也歡迎大家留言一起討論。

a. 子線程結(jié)束之后,'會(huì)喚醒主線程',父線程重新獲取cpu執(zhí)行權(quán),繼續(xù)運(yùn)行。

這里感謝kerwinX的留言,子線程結(jié)束后,子線程的this.notifyAll()會(huì)被調(diào)用,join()返回,父線程只要獲取到鎖和CPU,就可以繼續(xù)運(yùn)行下去了。

b. join() 將幾個(gè)并行的線程'合并為一個(gè)單線程'執(zhí)行。

我理解這個(gè)說法的意思,但是這樣描述只會(huì)讓讀者更難理解。

在調(diào)用 join() 方法的程序中,原來的多個(gè)線程仍然多個(gè)線程,并沒有發(fā)生“合并為一個(gè)單線程”。真正發(fā)生的是調(diào)用join() 的線程進(jìn)入 TIMED_WAITING 狀態(tài),等待 join() 所屬線程運(yùn)行結(jié)束后再繼續(xù)運(yùn)行。

一點(diǎn)感想:技術(shù)人員寫作技術(shù)文章時(shí),最好盡量避免使用過于口語化的詞匯。

因?yàn)檫@種詞匯歧義比較大,會(huì)讓讀者感到更加困惑或形成錯(cuò)誤的理解。

到此這篇關(guān)于Java中Thread.join()的使用方法的文章就介紹到這了,更多相關(guān)Java Thread.join()內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 欧美69| 国产aaaaa一级毛片 | 欧美做爰xxxⅹ性欧 欧美做爰免费大片在线观看 | 日本黄页网站免费大全 | 精品欧美一区二区三区免费观看 | 亚洲精品中文字幕一区在线 | 三级网址免费 | 香蕉网站狼人久久五月亭亭 | 一级黄色毛片播放 | 在线精品自拍 | www.久久综合 | 夜色综合| 亚洲精品成人一区二区www | 国产乱子伦在线观看不卡 | 国产成人啪精品视频免费网 | 丝袜美腿在线不卡视频播放 | 欧美一区在线观看视频 | 成人免费视频在线 | 韩国理伦一级毛片 | 国产自线一二三四2021 | 国产一区二区三区精品久久呦 | 国产伦一区二区三区四区久久 | 国产aⅴ一区二区 | 做爰www免费看视频 1024色淫免费视频 | 色成人亚洲 | 久久国产一级毛片一区二区 | 免费一级欧美片片线观看 | 91久久福利国产成人精品 | 仑乱高清在线一级播放 | 一区视频在线播放 | 亚洲国产欧美目韩成人综合 | 成人在线一区二区三区 | 爽死你个放荡粗暴小淫货双女视频 | 国产精品久久久久999 | 亚洲第一欧美 | 成年女人看片免费视频播放器 | 国内自拍tv在线 | 亚洲国产成人在线 | 亚洲欧美日韩国产一区二区精品 | 成人免费一区二区三区在线观看 | 97青青草原国产免费观看 |