中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Java中的Thread.join()

發布時間:2020-08-01 09:08:54 來源:億速云 閱讀:210 作者:小豬 欄目:開發技術

這篇文章主要講解了如何使用Java中的Thread.join(),內容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。

概要

本文分三個部分對Thread.join()進行分析:

1. join() 的示例和作用

2. join() 源碼分析

3. 對網上其他分析 join() 的文章提出疑問

1. join() 的示例和作用

1.1 示例

// 父線程
public class Parent {
 public static void main(String[] args) {
  // 創建child對象,此時child表示的線程處于NEW狀態
  Child child = new Child();
  // child表示的線程轉換為RUNNABLE狀態
  child.start();
  // 等待child線程運行完再繼續運行
  child.join();
 }
}
// 子線程
public class Child extends Thread {
 public void run() {
  // ...
 }
}

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

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

然后調用child.start()(child子線程狀態轉換為RUNNABLE);

再調用child.join(),此時,Parent父線程會等待child子線程運行完再繼續運行。

下圖是我總結的 Java 線程狀態轉換圖:

如何使用Java中的Thread.join()

1.2 join() 的作用

讓父線程等待子線程結束之后才能繼續運行。

我們來看看在 Java 7 Concurrency Cookbook 中相關的描述(很清楚地說明了 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.

當我們調用某個線程的這個方法時,這個方法會掛起調用線程,直到被調用線程結束執行,調用線程才會繼續執行。

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() 一共有三個重載版本,分別是無參、一個參數、兩個參數:

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)三個方法都被final修飾,無法被子類重寫。

(2)join(long),join(long, long) 是synchronized method,同步的對象是當前線程實例。

(2)無參版本和兩個參數版本最終都調用了一個參數的版本。

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

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

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

(4) join() 和 sleep() 一樣,可以被中斷(被中斷時,會拋出 InterrupptedException 異常);不同的是,join() 內部調用了 wait(),會出讓鎖,而 sleep() 會一直保持鎖。

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

調用鏈:Parent.main() -> child.join() -> child.join(0) -> child.wait(0)(此時 Parent線程會獲得 child 實例作為鎖,其他線程可以進入 child.join() ,但不可以進入 child.join(0), 因為child.join(0)是同步方法)。

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

一旦 child 線程不為 Active (狀態為 TERMINATED),child.notifyAll()會被調用-> child.wait(0)返回 -> child.join(0)返回 -> child.join()返回 -> Parent.main()繼續執行, 子線程會調用this.notify(),child.wait(0)會返回到child.join(0) ,child.join(0)會返回到 child.join(), child.join() 會返回到 Parent 父線程,Parent 父線程就可以繼續運行下去了。

3. 對網上其他分析 join() 的文章提出疑問

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

a. 子線程結束之后,"會喚醒主線程",父線程重新獲取cpu執行權,繼續運行。

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

b. join() 將幾個并行的線程"合并為一個單線程"執行。

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

在調用 join() 方法的程序中,原來的多個線程仍然多個線程,并沒有發生“合并為一個單線程”。真正發生的是調用join() 的線程進入 TIMED_WAITING 狀態,等待 join() 所屬線程運行結束后再繼續運行。

看完上述內容,是不是對如何使用Java中的Thread.join()有進一步的了解,如果還想學習更多內容,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南平市| 廉江市| 手游| 正镶白旗| 大港区| 安岳县| 勐海县| 南投市| 彰化县| 德庆县| 都江堰市| 明光市| 岑巩县| 互助| 噶尔县| 九台市| 分宜县| 陆良县| 贡觉县| 盈江县| 通渭县| 黄陵县| 江口县| 河源市| 陆丰市| 溧阳市| 策勒县| 巴青县| 海安县| 长治县| 荣成市| 芮城县| 涟源市| 隆化县| 申扎县| 山东省| 岗巴县| 齐齐哈尔市| 宿迁市| 冕宁县| 东乡族自治县|