欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?Thread中join方法使用舉例詳解

 更新時間:2025年07月26日 09:26:37   作者:干凈的壞蛋  
Java Thread中join()方法主要是讓調(diào)用改方法的thread完成run方法里面的東西后,在執(zhí)行join()方法后面的代碼,這篇文章主要介紹了Java?Thread中join方法使用的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

join() 方法是 Java 并發(fā)編程中一個非常重要且基礎(chǔ)的方法,它允許一個線程等待另一個線程執(zhí)行完成。理解它的工作原理和使用場景對于編寫健壯的多線程應(yīng)用程序至關(guān)重要。

1.join()方法的定義和作用

join()java.lang.Thread 類的一個實例方法。它的核心作用是阻塞當(dāng)前正在執(zhí)行的線程(我們稱之為“主線程”,盡管它可以是任何線程),直到調(diào)用 join() 方法的那個線程(我們稱之為“目標(biāo)線程”)執(zhí)行完畢。

簡單來說,如果線程 A 的代碼中調(diào)用了線程 B 的 join() 方法(即 B.join()),那么線程 A 就會進入等待狀態(tài),直到線程 B 執(zhí)行結(jié)束,線程 A 才會從 B.join() 這行代碼繼續(xù)往下執(zhí)行。

這就像在一個接力賽中,下一棒的選手(線程 A)必須等待上一棒的選手(線程 B)跑完自己的賽程并交接后,才能開始跑。

2.join()方法的三個重載版本

Thread 類提供了三個版本的 join() 方法:

  1. public final void join()

    • 這是最常用的版本。它會一直等待,直到目標(biāo)線程執(zhí)行完畢。
    • 它會拋出 InterruptedException,這意味著等待中的線程可能會被中斷。
  2. public final synchronized void join(long millis)

    • 這是一個帶超時參數(shù)的版本。它會等待目標(biāo)線程執(zhí)行,但最多只等待指定的毫秒數(shù)。
    • 如果目標(biāo)線程在指定的超時時間內(nèi)執(zhí)行完畢,當(dāng)前線程會立即繼續(xù)執(zhí)行。
    • 如果超過了指定的毫秒數(shù),目標(biāo)線程還未執(zhí)行完,當(dāng)前線程也會停止等待,繼續(xù)執(zhí)行。
    • 同樣會拋出 InterruptedException。
  3. public final synchronized void join(long millis, int nanos)

    • 這個版本提供了更精確的超時控制,可以指定毫秒和納秒。
    • 功能與 join(long millis) 類似,只是提供了更高精度的時間控制。

3.join()方法的工作原理 (深入分析)

你可能會好奇,join() 是如何實現(xiàn)線程等待的?它的底層原理是什么?

  1. isAlive() 檢查: 當(dāng)你在線程 A 中調(diào)用 threadB.join() 時,join() 方法內(nèi)部會首先檢查 threadB 是否還活著 (isAlive())。如果 threadB 已經(jīng)執(zhí)行完畢(或者從未啟動),isAlive() 會返回 false,那么 join() 方法會立即返回,線程 A 不會進行任何等待。

  2. wait() 循環(huán)等待: 如果 isAlive() 返回 true,join() 方法會進入一個循環(huán)。在這個循環(huán)里,它會調(diào)用目標(biāo)線程對象(threadB)的 wait() 方法。

    • 關(guān)鍵點: join() 方法是一個 synchronized 方法。當(dāng)線程 A 調(diào)用 threadB.join() 時,它會獲取 threadB 這個對象的鎖。然后,join() 方法內(nèi)部調(diào)用 threadB.wait(),這會導(dǎo)致線程 A 釋放 threadB 的鎖,并進入 threadB 對象的等待集(Wait Set)中,狀態(tài)變?yōu)?WAITINGTIMED_WAITING。
  3. JVM 負(fù)責(zé)喚醒: 當(dāng)目標(biāo)線程 threadBrun() 方法執(zhí)行完畢,準(zhǔn)備退出時,Java 虛擬機(JVM)會在其內(nèi)部自動調(diào)用 threadBnotifyAll() 方法。

    • 這個 notifyAll() 會喚醒所有正在等待 threadB 對象鎖的線程,當(dāng)然也包括了之前因調(diào)用 join() 而等待的線程 A。
  4. 重新獲取鎖并退出: 線程 A 被喚醒后,會嘗試重新獲取 threadB 的對象鎖。一旦獲取成功,它會從 wait() 方法返回,并退出 join() 的循環(huán),從而結(jié)束等待,繼續(xù)執(zhí)行后續(xù)代碼。

總結(jié)一下核心機制: join() 的實現(xiàn)巧妙地利用了 Java 的內(nèi)置鎖(synchronized)和 wait()/notifyAll() 協(xié)作機制。它將線程間的執(zhí)行順序問題,轉(zhuǎn)化為了經(jīng)典的“生產(chǎn)者-消費者”模式中的線程同步問題。

4. 為什么要使用join()?使用場景

join() 的主要應(yīng)用場景是協(xié)調(diào)線程間的執(zhí)行順序。當(dāng)你需要確保一個或多個前置任務(wù)(在子線程中執(zhí)行)完成后,主線程才能繼續(xù)執(zhí)行后續(xù)任務(wù)時,join() 就非常有用。

常見場景:

  • 數(shù)據(jù)初始化: 主線程啟動多個子線程去分別加載不同的資源或執(zhí)行初始化計算。主線程需要等待所有初始化工作完成后,才能使用這些資源去執(zhí)行核心業(yè)務(wù)邏輯。
  • 分塊處理: 一個大任務(wù)被拆分成多個小任務(wù),每個小任務(wù)交給一個子線程處理。主線程需要等待所有子線程處理完畢后,對結(jié)果進行匯總和合并。
  • 確保流程順序: 在一個復(fù)雜的業(yè)務(wù)流程中,步驟 B 必須在步驟 A 執(zhí)行完畢后才能開始。如果 A 和 B 在不同的線程中,那么 B 所在的線程就需要 join() A 所在的線程。

5. 代碼示例

示例 1: 等待單個線程

public class JoinExample {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主線程開始運行...");

        Thread workerThread = new Thread(() -> {
            System.out.println("子線程開始工作...");
            try {
                // 模擬耗時操作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子線程工作完成。");
        });

        workerThread.start(); // 啟動子線程

        System.out.println("主線程調(diào)用 join() 等待子線程...");
        workerThread.join(); // 關(guān)鍵:主線程在此處阻塞,等待 workerThread 執(zhí)行完畢

        System.out.println("主線程在子線程完成后繼續(xù)運行。");
    }
}

輸出:

主線程開始運行...
主線程調(diào)用 join() 等待子線程...
子線程開始工作...
// (等待約 2 秒)
子線程工作完成。
主線程在子線程完成后繼續(xù)運行。

示例 2: 等待多個線程

public class MultiJoinExample {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主線程開始...");

        Thread t1 = new Thread(() -> {
            System.out.println("線程1 開始處理...");
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
            System.out.println("線程1 處理完畢。");
        });

        Thread t2 = new Thread(() -> {
            System.out.println("線程2 開始處理...");
            try { Thread.sleep(2000); } catch (InterruptedException e) {}
            System.out.println("線程2 處理完畢。");
        });

        // 啟動所有線程
        t1.start();
        t2.start();

        System.out.println("主線程等待所有子線程完成...");

        // 等待 t1 和 t2
        t1.join();
        t2.join();

        System.out.println("所有子線程處理完畢,主線程繼續(xù)執(zhí)行。");
    }
}

輸出:

主線程開始...
主線程等待所有子線程完成...
線程1 開始處理...
線程2 開始處理...
// (等待約 1 秒)
線程1 處理完畢。
// (再等待約 1 秒)
線程2 處理完畢。
所有子線程處理完畢,主線程繼續(xù)執(zhí)行。

6.InterruptedException的處理

join() 方法會拋出 InterruptedException。這是因為正在等待的線程(調(diào)用 join() 的線程)自身可能會被其他線程中斷 (interrupt())。

當(dāng)一個線程在 join() 等待期間被中斷時,join() 方法會立即拋出 InterruptedException。在 catch 塊中,通常需要處理這個中斷信號。一個好的實踐是重新設(shè)置當(dāng)前線程的中斷狀態(tài),以便上層調(diào)用者能夠知道發(fā)生了中斷。

try {
    workerThread.join();
} catch (InterruptedException e) {
    // 捕獲到中斷異常
    System.out.println("主線程在等待期間被中斷了!");
    // 恢復(fù)中斷狀態(tài),這是一種良好的編程實踐
    Thread.currentThread().interrupt();
}

總結(jié)

特性描述
目的阻塞當(dāng)前線程,等待目標(biāo)線程執(zhí)行完畢。
核心原理基于 synchronizedwait() / notifyAll() 機制。
版本join(), join(long millis), join(long millis, int nanos)
使用場景需要保證線程執(zhí)行順序,如等待子任務(wù)完成、數(shù)據(jù)初始化等。
異常拋出 InterruptedException,需要妥善處理線程中斷。
關(guān)鍵點t.join() 是讓當(dāng)前線程等待 t 線程,而不是讓 t 線程等待。

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

相關(guān)文章

  • Spring中Cache的使用方法詳解

    Spring中Cache的使用方法詳解

    這篇文章主要介紹了Spring中Cache的使用方法詳解,Spring Cache 是一個框架,實現(xiàn)了基于注解的緩存功能,只需要簡單地加一個注解,就能實現(xiàn)緩存功能,Spring Cache 提供了一層抽象,底層可以切換不同的緩存實現(xiàn),需要的朋友可以參考下
    2024-01-01
  • 淺談Java平臺無關(guān)性

    淺談Java平臺無關(guān)性

    這篇文章主要介紹了淺談Java平臺無關(guān)性,對此感興趣的同學(xué),可以多了解一下
    2021-04-04
  • Go反射底層原理及數(shù)據(jù)結(jié)構(gòu)解析

    Go反射底層原理及數(shù)據(jù)結(jié)構(gòu)解析

    這篇文章主要介紹了Go反射底層原理及數(shù)據(jù)結(jié)構(gòu)解析,反射的實現(xiàn)和interface的組成很相似,都是由“類型”和“數(shù)據(jù)值”構(gòu)成,下面小編分享更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-06-06
  • 總結(jié)java多線程之互斥與同步解決方案

    總結(jié)java多線程之互斥與同步解決方案

    文中總結(jié)了線程互斥與同步,synchronized使用細(xì)節(jié)及原理,Reentrylock使用細(xì)節(jié)等知識,對解決Java多線程互斥與同步等問題很有效,,需要的朋友可以參考下
    2021-05-05
  • 深入淺析Mybatis與Hibernate的區(qū)別與用途

    深入淺析Mybatis與Hibernate的區(qū)別與用途

    這篇文章主要介紹了Mybatis與Hibernate的區(qū)別與用途的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • java?socket實現(xiàn)局域網(wǎng)聊天

    java?socket實現(xiàn)局域網(wǎng)聊天

    這篇文章主要為大家詳細(xì)介紹了java?socket實現(xiàn)局域網(wǎng)聊天,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • TC?集群Seata1.6高可用架構(gòu)源碼解析

    TC?集群Seata1.6高可用架構(gòu)源碼解析

    這篇文章主要為大家介紹了TC?集群Seata1.6高可用架構(gòu)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • java 實現(xiàn)雙向鏈表實例詳解

    java 實現(xiàn)雙向鏈表實例詳解

    這篇文章主要介紹了java 實現(xiàn)雙向鏈表實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Sentinel中三種流控模式的使用詳解

    Sentinel中三種流控模式的使用詳解

    這篇文章主要為大家詳細(xì)介紹了Sentinel中三種流控模式(預(yù)熱模式,排隊等待模式和熱點規(guī)則)的使用,文中的示例代碼講解詳細(xì),感興趣的可以了解下
    2023-08-08
  • Spark調(diào)優(yōu)多線程并行處理任務(wù)實現(xiàn)方式

    Spark調(diào)優(yōu)多線程并行處理任務(wù)實現(xiàn)方式

    這篇文章主要介紹了Spark調(diào)優(yōu)多線程并行處理任務(wù)實現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08

最新評論