国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

[Java]線程生命周期與線程通信

這篇具有很好參考價(jià)值的文章主要介紹了[Java]線程生命周期與線程通信。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

【版權(quán)聲明】未經(jīng)博主同意,謝絕轉(zhuǎn)載?。ㄕ堊鹬卦瓌?chuàng),博主保留追究權(quán))
https://www.cnblogs.com/cnb-yuchen/p/18162522
出自【進(jìn)步*于辰的博客】

線程生命周期與進(jìn)程有諸多相似,所以我們很容易將兩者關(guān)聯(lián)理解并混淆,一些細(xì)節(jié)之處確有許多不同,因?yàn)榫€程調(diào)度與進(jìn)程調(diào)度雖都由CPU完成,但兩者并不相同。
特意耗費(fèi)一些時(shí)間,系統(tǒng)地對線程生命周期與線程通信進(jìn)行梳理、整理。

目錄
  • 1、線程生命周期
    • 1.1 JDK1.8版本
    • 1.2 早期版本(JDK1.2之前)
    • 1.3 落到實(shí)處
  • 2、線程通信
    • 2.1 使用 volatile 關(guān)鍵字
    • 2.2 使用Object類的wait()notify()
    • 2.3 使用JUC工具類 CountDownLatch
    • 2.4 使用 ReentrantLock 結(jié)合 Condition
    • 2.5 使用 LockSupport
  • 最后

1、線程生命周期

1.1 JDK1.8版本

啟發(fā)博文:《線程的生命周期及五種基本狀態(tài)》(轉(zhuǎn)發(fā))。

引用其中一張線程生命周期圖:

[Java]線程生命周期與線程通信

在啟發(fā)博文中,博主對線程五大狀態(tài)和生命周期進(jìn)行了很詳細(xì)的說明,大家可以先行查閱。

這張圖對線程生命周期總結(jié)得比較全面,我一一梳理、核對后覺得稍有不妥之處,略作修改后作如下圖:

[Java]線程生命周期與線程通信

在此我先簡述一下我對線程五個(gè)狀態(tài)的理解:

  1. new(新建):在線程創(chuàng)建后、啟動(dòng)(start())之前所處的狀態(tài)。
  2. Runnable(就緒):線程新建后并不是直接開始運(yùn)行,而是被加入到等待隊(duì)列,等待線程調(diào)度(等待CPU),此時(shí)就處于就緒狀態(tài)。因此,這兩種情況將進(jìn)入就緒狀態(tài):(1)調(diào)用start();(2)因某種原因(如:線程通信、等待IO)進(jìn)入阻塞狀態(tài)后重新等待運(yùn)行。
  3. Running(運(yùn)行):線程正在運(yùn)行時(shí)的狀態(tài)。
  4. Blocked(阻塞):線程因某種原因(如:線程通信、等待IO)而停止運(yùn)行后進(jìn)入的狀態(tài)。
  5. Dead(死亡):線程正常結(jié)束或異常終止后所處的狀態(tài)。

相信大家在閱讀完以上簡述后,對線程的五大狀態(tài)已經(jīng)有了一個(gè)初步的認(rèn)識(shí),那狀態(tài)間是如何轉(zhuǎn)換的?又怎么理解呢?對于這兩個(gè)問題,由于涉及到各個(gè)方法的業(yè)務(wù)和底層邏輯,本篇文章不便一一詳述。如果大家想要進(jìn)一步了解,可移步 → 《Thread類源碼解析》。

其中,Blocked狀態(tài)可能不太好理解,那位博主將其劃分為三種情況:等待阻塞、同步阻塞和其他阻塞。我贊同,大家可移步啟發(fā)博文查閱詳述,在此不贅述,僅稍作說明:

三種阻塞情況的變動(dòng)主要因“線程通信”引起,變化僅是阻塞情況的變化,狀態(tài)不變,仍是Blocked。

點(diǎn)出兩個(gè)問題:
1:為什么調(diào)用notify()/notifyAll(),線程由等待Blocked變?yōu)?code>鎖定Blocked?
文章排版考慮,在下文【使用Object類的wait()notify()】中說明。

2:interrupt()可中斷線程,那么可中斷正在阻塞的線程嗎?
本質(zhì)上說,可以,但會(huì)拋出異常(即不可以,故我未將其寫入上圖),在上文我給出的《Thread類源碼解析》文章中有具體說明。

1.2 早期版本(JDK1.2之前)

相信能堅(jiān)持閱讀到這的博友,大部分是站在Java門檻上或剛?cè)腴T不久的Java小白,你們現(xiàn)在了解和學(xué)習(xí)線程生命周期,獲得的是已更新、迭代后的知識(shí)。個(gè)人認(rèn)為,大家不需要掌握已過時(shí)的知識(shí),但不能不了解,我先拋出兩個(gè)問題:

  1. “掛起”狀態(tài)是什么?怎么不在線程五大狀態(tài)之列?
  2. 相信大家在一些資料中,可能見到過suspend()、resume()、stop()destroy()這4個(gè)方法,怎么上圖中沒有?為什么不用了?

當(dāng)然是有的,只是過時(shí)了,所以沒放上去,完整的圖是這樣:

[Java]線程生命周期與線程通信

OK,現(xiàn)在回答那兩個(gè)問題。

“掛起”狀態(tài)是一種類似Runnable(就緒)狀態(tài)的狀態(tài),不同之處是進(jìn)入就緒狀態(tài)的線程,會(huì)釋放所持有的“同步鎖”,而“掛起”狀態(tài)不會(huì),“掛起”狀態(tài)相當(dāng)于“暫?!?,故容易導(dǎo)致“死鎖”。

為什么那4個(gè)方法會(huì)被放棄?
我尋得一答案,闡述得很詳細(xì),我便不班門弄斧了,看這里 → 《《Java面向?qū)ο缶幊獭穼?dǎo)讀-Thread類的被廢棄的suspend()、resume()和stop()方法》(轉(zhuǎn)發(fā))。

我補(bǔ)充一張圖:
[Java]線程生命周期與線程通信

1.3 落到實(shí)處

所謂“落到實(shí)處”,就是要想掌握線程生命周期,光如上文夸夸其談當(dāng)然還不夠,我們要把線程五大狀態(tài)和狀態(tài)間轉(zhuǎn)換對應(yīng)到Thread源碼中才行。

如下圖:

[Java]線程生命周期與線程通信

我自己感覺有點(diǎn)亂,源碼所示如此。

當(dāng)然,這不是完整圖,圖中狀態(tài)間轉(zhuǎn)換僅做了部分舉例。在此,我不作說明,相信用心看到這里的博友可以大致理解。當(dāng)然,也不便做出說明,因?yàn)槲夷壳皩σ恍┓椒ǖ牧私馔A粼凇皶?huì)用”的程度(見下文),并未對相應(yīng)源碼進(jìn)行解析。

補(bǔ)充一點(diǎn):
大家對比這張“狀態(tài)圖”和上文線程生命周期圖,大家會(huì)發(fā)現(xiàn)有點(diǎn)對不上。

其實(shí),WAITING就是Runnable(就緒),在線程生命周期中,一般不說“就緒”,“就緒”是進(jìn)程生命周期中的術(shù)語,上文這般使用是為了方便大家理解;而RUNNABLE就是Running。

2、線程通信

啟發(fā)博文:《線程間通信的幾種實(shí)現(xiàn)方式》(轉(zhuǎn)發(fā))。

我暫未整理“線程通信”相關(guān)理論,故下文將以示例的形式進(jìn)行闡述。

注:以下5個(gè)示例都成功實(shí)現(xiàn)線程通信,輸出結(jié)果是:

喚醒t1
t1已喚醒

2.1 使用 volatile 關(guān)鍵字

示例:

private static volatile boolean isWait = true;

public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        while (true)
            if (!isWait) {
                System.out.println("t1已喚醒");
                break;
            }
    });
    Thread t2 = new Thread(() -> {
        System.out.println("喚醒t1");
        isWait = false;
    });
    t1.start();
    t2.start();
}

如果大家不了解volatile關(guān)鍵字,看這里。

這里線程通信利用的是volatile關(guān)鍵字“保證可見性”的原理。

2.2 使用Object類的wait()和notify()

示例:

Object lock = new Object();
Thread t1 = new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("t1已喚醒");
    }
});
Thread t2 = new Thread(() -> {
    synchronized (lock) {
        System.out.println("喚醒t1");
//      lock.notify();// 喚醒等待隊(duì)列中的一個(gè)線程,不一定是 t1
        lock.notifyAll();
    }
});
t1.start();
t2.start();

大家還記得我在【1.1】中點(diǎn)出的這個(gè)問題嗎?

為什么調(diào)用notify()/notifyAll(),線程由等待Blocked變?yōu)?code>鎖定Blocked?

答案就在以上代碼的執(zhí)行過程中,我給大家捋一捋。

1、t1、t2都執(zhí)行,t1在t2之前啟動(dòng),先獲得同步鎖,t2阻塞。
2、t1調(diào)用wait()進(jìn)入等待狀態(tài),釋放同步鎖,同步鎖由t2獲得,t2開始運(yùn)行。
3、t2調(diào)用notify()喚醒t1,但此時(shí)同步鎖仍由t2持有,t1繼續(xù)等待。
4、t2運(yùn)行完,釋放同步鎖,由t1獲得,t1開始運(yùn)行。

OK,就是第3點(diǎn)。

為什么一定要同步鎖?
因?yàn)?code>wait()與notify()的底層邏輯要求必須是“先等待,再喚醒”,同步鎖可以保證流程的正常執(zhí)行。難道真的不能去掉同步鎖?例如這樣:

Object lock = new Object();
Thread t1 = new Thread(() -> {
    try {
        lock.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("t1已喚醒");
});
Thread t2 = new Thread(() -> {
    System.out.println("喚醒t1");
    lock.notifyAll();
});
t1.start();
t1.join();
t2.start();

很明顯,不行。這樣就出現(xiàn)了“死鎖”。

t1 等待被喚醒,主線程等待 t1 運(yùn)行完。

因此,必須使用同步鎖,且必須是同一把鎖(lock)、

2.3 使用JUC工具類 CountDownLatch

示例:

CountDownLatch latch = new CountDownLatch(1);// 這個(gè) 1 是同步狀態(tài),類似synchronized中的 count
Thread t1 = new Thread(() -> {
    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("t1已喚醒");
});
Thread t2 = new Thread(() -> {
    System.out.println("喚醒t1");
    latch.countDown();
});
t1.start();
t2.start();

可見,無需同步鎖。為何?這就要涉及CountDownLatch類的源碼了。當(dāng)然,我們暫且不用深入了解,理解其底層邏輯即可。

看這里 → 《這一次,徹底搞懂Java中的synchronized關(guān)鍵字》(轉(zhuǎn)發(fā))。

大家找到【1.同步代碼塊】這一欄,底層邏輯相似。

2.4 使用 ReentrantLock 結(jié)合 Condition

示例:

Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();

Thread t1 = new Thread(() -> {
    lock.lock();
    try {
        cond.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("t1已喚醒");
    lock.unlock();
});
Thread t2 = new Thread(() -> {
    lock.lock();
    System.out.println("喚醒t1");
    cond.signal();
    lock.unlock();
});
t1.start();
t2.start();

這兩條代碼合起來相當(dāng)于同步鎖:

lock.lock();
...
lock.unlock();

2.5 使用 LockSupport

示例:

Thread t1 = new Thread(() -> {
    LockSupport.park();
    System.out.println("t1已喚醒");
});
Thread t2 = new Thread(() -> {
    System.out.println("喚醒t1");
    LockSupport.unpark(t1);
});
t1.start();
t2.start();

可見,LockSupport類不關(guān)注是否“在等待”。

最后

本文中的例子是為了方便大家理解和闡述知識(shí)點(diǎn)而簡單舉出的,旨在“闡明知識(shí)點(diǎn)”,簡單為主,并不一定有實(shí)用性。

如果大家想要快速地掌握這些知識(shí)點(diǎn),我的建議是“自測中理解”。

本文完結(jié)。文章來源地址http://www.zghlxwxcb.cn/news/detail-860284.html

到了這里,關(guān)于[Java]線程生命周期與線程通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C語言趣味教程】(4) 變量:代碼注釋 | 變量的聲明 | 初始化與賦值 | 作用域與生命周期 | 局部變量與全局變量

    【C語言趣味教程】(4) 變量:代碼注釋 | 變量的聲明 | 初始化與賦值 | 作用域與生命周期 | 局部變量與全局變量

    ? ?? 《C語言趣味教程》?? 猛戳訂閱?。?! 0x00 引入:注釋的作用 \\\"程序員最討厭兩種人:一種是不寫注釋的人,一種是讓我寫注釋的人。\\\" 相信大家對注釋早已有所耳聞,對于注釋,C 語言有兩種注釋風(fēng)格,我們下面會(huì)逐個(gè)講解。 ? 但在這之前,我們先來了解了解注釋的作

    2024年02月15日
    瀏覽(27)
  • 【React】組件生命周期、組件通信、setState

    【React】組件生命周期、組件通信、setState

    ? 組件化思想的應(yīng)用: ? ? 有了組件化的思想,我們在之后的開發(fā)中就要充分的利用它。 ? ? 盡可能的將頁面拆分成一個(gè)個(gè)小的、可復(fù)用的組件。 ? ? 這樣讓我們的代碼更加方便組織和管理,并且擴(kuò)展性也更強(qiáng)。 ? React的組件相對于Vue更加的靈活和多樣,按照不同的

    2024年01月20日
    瀏覽(20)
  • 高級(jí)進(jìn)階多線程——多任務(wù)處理、線程狀態(tài)(生命周期)、三種創(chuàng)建多線程的方式

    高級(jí)進(jìn)階多線程——多任務(wù)處理、線程狀態(tài)(生命周期)、三種創(chuàng)建多線程的方式

    Java中的多線程是一個(gè)同時(shí)執(zhí)行多個(gè)線程的進(jìn)程。線程是一個(gè)輕量級(jí)的子進(jìn)程,是最小的處理單元。多進(jìn)程和多線程都用于實(shí)現(xiàn)多任務(wù)處理。 但是,一般使用多線程而不是多進(jìn)程,這是因?yàn)榫€程使用共享內(nèi)存區(qū)域。它們不分配單獨(dú)的內(nèi)存區(qū)域以節(jié)省內(nèi)存,并且線程之間的上下

    2024年02月13日
    瀏覽(25)
  • 【微信小程序】生命周期,插槽和組件間通信

    【微信小程序】生命周期,插槽和組件間通信

    1.1 組件全部的生命周期函數(shù) 小程序組件可用的全部生命周期如下表所示 生命周期函數(shù) 參數(shù) 描述說明 created 無 在組件實(shí)例剛剛被創(chuàng)建時(shí)執(zhí)行 attached 無 在組件實(shí)例進(jìn)入頁面節(jié)點(diǎn)樹時(shí)執(zhí)行 ready 無 在組件在視圖層布局完成后執(zhí)行 moved 無 在組件實(shí)例被移動(dòng)到節(jié)點(diǎn)樹另一個(gè)位置時(shí)

    2024年02月11日
    瀏覽(95)
  • unity的C#學(xué)習(xí)——多線程編程(線程的生命周期、創(chuàng)建與管理)與線程相關(guān)類

    多線程編程是 C# 一個(gè)比較難且涵蓋面比較廣的知識(shí)點(diǎn),本文整理倉促而且屬于筆記向博客,有些地方必然還存在不嚴(yán)謹(jǐn)和錯(cuò)誤,本人會(huì)在日后的使用過程中不斷完善。如果發(fā)現(xiàn)問題或有改進(jìn)意見可以在評論區(qū)提出,我會(huì)及時(shí)修改。 線程是程序的執(zhí)行流程,也被稱為 輕量級(jí)進(jìn)

    2024年02月12日
    瀏覽(30)
  • 【微信小程序】父子組件的創(chuàng)建、通信與事件觸發(fā);組件生命周期

    【微信小程序】父子組件的創(chuàng)建、通信與事件觸發(fā);組件生命周期

    關(guān)于微信小程序中父子組件的創(chuàng)建、傳值,以及涉及到的組件生命周期。 組件的使用可以 提高開發(fā)效率 并 確保功能在各個(gè)頁面上的應(yīng)用和修改的一致性 。 例如,對于一些重復(fù)的功能,比如頂部導(dǎo)航欄或評論區(qū),將其提煉成組件后,我們只需要在不同的頁面中引用該組件,

    2024年02月03日
    瀏覽(99)
  • vue04---計(jì)算屬性/監(jiān)聽(偵聽)屬性/Vue生命周期/組件介紹和使用/組件間通信/ref屬性

    # 1 計(jì)算屬性是基于它們的依賴變量進(jìn)行緩存的 # 2 計(jì)算屬性只有在它的相關(guān)依賴變量發(fā)生改變時(shí)才會(huì)重新求值,否則不會(huì)變(函數(shù)只要頁面變化,就會(huì)重新運(yùn)算) # 3 計(jì)算屬性就像Python中的property,可以把方法/函數(shù)偽裝成屬性 # 4 計(jì)算屬性,必須有返回值 基本使用 重寫過濾案

    2024年02月08日
    瀏覽(27)
  • 011:Mapbox GL兩種方式隱藏logo和版權(quán),個(gè)性化版權(quán)的聲明

    011:Mapbox GL兩種方式隱藏logo和版權(quán),個(gè)性化版權(quán)的聲明

    第011個(gè) 點(diǎn)擊查看專欄目錄 本示例的目的是介紹演示如何在vue+mapbox中用兩種方式隱藏logo和版權(quán),并個(gè)性化版權(quán)的聲明 。 直接復(fù)制下面的 vue+mapbox源代碼,操作2分鐘即可運(yùn)行實(shí)現(xiàn)效果 示例效果

    2023年04月17日
    瀏覽(38)
  • 【Java基礎(chǔ)】Java對象的生命周期

    【Java基礎(chǔ)】Java對象的生命周期

    一個(gè)類通過編譯器將一個(gè)Java文件編譯為Class字節(jié)碼文件,然后通過JVM中的解釋器編譯成不同操作系統(tǒng)的機(jī)器碼。雖然操作系統(tǒng)不同,但是基于解釋器的虛擬機(jī)是相同的。java類的生命周期就是指一個(gè)class文件加載到類文件注銷整個(gè)過程。 一個(gè)java類的完整的生命周期會(huì)經(jīng)歷加載

    2024年02月12日
    瀏覽(36)
  • JVM包含哪幾部分?JVM內(nèi)存模型?線程的生命周期? 對Spring AOP的理解?布隆過濾器

    JVM包含哪幾部分?JVM內(nèi)存模型?線程的生命周期? 對Spring AOP的理解?布隆過濾器

    JVM由三部分組成:類加載子系統(tǒng)、執(zhí)行引擎、運(yùn)行時(shí)數(shù)據(jù)區(qū)。 類加載子系統(tǒng):可以根據(jù)指定的全限定名來載入類或接口。 執(zhí)行引擎:負(fù)責(zé)執(zhí)行那些包含在被載入類的方法中的指令。 運(yùn)行時(shí)數(shù)據(jù)區(qū):當(dāng)程序運(yùn)行時(shí),JVM需要內(nèi)存來存儲(chǔ)許多內(nèi)容,例如:字節(jié)碼、對象、參數(shù)、返

    2024年02月16日
    瀏覽(50)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包