最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程與并發(fā)完整代碼詳解

 更新時(shí)間:2026年06月29日 10:48:54   作者:匿名俠士  
Java并發(fā)編程和多線程是高級(jí)開(kāi)發(fā)中的一個(gè)重要部分,涉及多線程的創(chuàng)建、線程協(xié)同、線程安全、性能優(yōu)化、并發(fā)工具等內(nèi)容,這篇文章主要介紹了Java多線程與并發(fā)的相關(guān)資料,需要的朋友可以參考下

一、多線程基礎(chǔ):優(yōu)缺點(diǎn)與核心代價(jià)

1. 核心優(yōu)點(diǎn)

  • 資源利用率更高:CPU空閑時(shí)可調(diào)度其他線程執(zhí)行,避免硬件資源浪費(fèi)(如IO等待時(shí)CPU不閑置)。

  • 程序設(shè)計(jì)更簡(jiǎn)潔:異步場(chǎng)景(如文件下載、接口調(diào)用)可通過(guò)多線程拆分任務(wù),簡(jiǎn)化復(fù)雜邏輯。

  • 程序響應(yīng)更快:UI界面、服務(wù)端程序可通過(guò)多線程避免主線程阻塞,提升用戶/調(diào)用方體驗(yàn)。

2. 主要代價(jià)(易忽略細(xì)節(jié))

  • 設(shè)計(jì)復(fù)雜度上升:需處理線程安全、同步、死鎖、線程通信等問(wèn)題,調(diào)試難度增加。

  • 上下文切換開(kāi)銷:線程切換時(shí)需保存/恢復(fù)線程上下文(棧、寄存器等),消耗CPU資源(高頻切換會(huì)嚴(yán)重影響性能)。

  • 額外資源消耗:每個(gè)線程需占用棧內(nèi)存(默認(rèn)1M左右)、內(nèi)核對(duì)象,過(guò)多線程會(huì)導(dǎo)致內(nèi)存溢出(OOM)。

二、線程創(chuàng)建與啟動(dòng)(關(guān)鍵細(xì)節(jié)補(bǔ)全)

1. 兩種標(biāo)準(zhǔn)實(shí)現(xiàn)方式

方式1:繼承Thread類

class MyThread extends Thread {
    @Override
    public void run() { 
        // 線程執(zhí)行的業(yè)務(wù)邏輯(線程體)
    }
}
// 啟動(dòng)線程:調(diào)用start(),而非run()
new MyThread().start();

方式2:實(shí)現(xiàn)Runnable接口(推薦)

class MyTask implements Runnable {
    @Override
    public void run() {
        // 線程執(zhí)行的業(yè)務(wù)邏輯(解耦:任務(wù)與線程分離)
    }
}
// 啟動(dòng)線程:將任務(wù)傳入Thread實(shí)例
new Thread(new MyTask()).start();

2. 選型建議(筆記補(bǔ)充)

優(yōu)先選擇實(shí)現(xiàn)Runnable接口,原因如下:

  • 解耦:任務(wù)邏輯(Runnable)與線程控制(Thread)分離,便于復(fù)用、維護(hù)。

  • 適配高級(jí)特性:線程池、Future等JUC工具類僅支持Runnable接口,可降低后續(xù)擴(kuò)展成本。

  • 規(guī)避單繼承限制:Java是單繼承語(yǔ)言,繼承Thread會(huì)占用唯一的繼承名額,影響類的擴(kuò)展性。

3. 經(jīng)典錯(cuò)誤(必記)

調(diào)用run()方法而非start()

直接調(diào)用run()只是普通方法調(diào)用(運(yùn)行在當(dāng)前線程),不會(huì)啟動(dòng)新線程;start()才會(huì)觸發(fā)JVM創(chuàng)建新線程,執(zhí)行run()方法。

三、線程安全核心:競(jìng)態(tài)條件與臨界區(qū)

1. 核心概念

  • 競(jìng)態(tài)條件:多線程競(jìng)爭(zhēng)同一共享資源時(shí),執(zhí)行結(jié)果依賴線程執(zhí)行順序(如多線程自增同一個(gè)變量,結(jié)果可能小于預(yù)期值)。

  • 臨界區(qū):導(dǎo)致競(jìng)態(tài)條件的代碼片段(即多個(gè)線程共享資源并可能修改資源的代碼塊)。

2. 本質(zhì)原因

共享資源的“讀-改-寫(xiě)”復(fù)合操作非原子性(如count++,實(shí)際分為3步:讀count值→自增→寫(xiě)回count,多線程交錯(cuò)執(zhí)行會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)亂)。

四、線程安全判定:線程控制逃逸規(guī)則(重點(diǎn))

核心判定原則:若一個(gè)資源(對(duì)象、文件、數(shù)據(jù)庫(kù)連接等)的創(chuàng)建、使用、銷毀,全程在同一個(gè)線程內(nèi)完成,且不會(huì)逃逸到線程外部(即其他線程無(wú)法訪問(wèn)該資源),則該資源的使用是線程安全的。

1. 天生線程安全的場(chǎng)景

  • 局部基本變量:存儲(chǔ)在線程私有棧中,不共享,天然安全(如方法內(nèi)的int、boolean變量)。

  • 局部對(duì)象引用(無(wú)逃逸):對(duì)象本身在堆內(nèi)存(共享區(qū)域),但引用僅存在于當(dāng)前線程棧,且未通過(guò)返回值、參數(shù)傳遞等方式暴露給其他線程,線程安全。

2. 天生線程不安全的場(chǎng)景

對(duì)象成員變量(存儲(chǔ)在堆內(nèi)存,多線程可通過(guò)對(duì)象引用訪問(wèn)并修改,若未加同步,必存在線程安全問(wèn)題)。

五、不可變性與線程安全(補(bǔ)全細(xì)節(jié))

  • 核心結(jié)論:只讀共享的資源不會(huì)產(chǎn)生線程安全問(wèn)題;不可變對(duì)象(狀態(tài)一旦創(chuàng)建無(wú)法修改)天然線程安全(如String、Integer等包裝類)。

  • 關(guān)鍵提醒:不可變對(duì)象的引用不一定安全!例如:AtomicReference<String> ref = new AtomicReference<>("a");,ref引用本身可被多線程修改(需用原子類保護(hù)),但引用指向的String對(duì)象本身不可變。

六、synchronized同步機(jī)制(核心,筆記細(xì)節(jié)補(bǔ)全)

synchronized是Java原生的悲觀鎖,通過(guò)“互斥”保證臨界區(qū)原子性,同時(shí)保證可見(jiàn)性(解鎖前的修改對(duì)后續(xù)加鎖線程可見(jiàn))和可重入性。

1. 四種作用范圍(附實(shí)例與鎖對(duì)象)

作用范圍鎖對(duì)象實(shí)例代碼說(shuō)明
實(shí)例方法同步當(dāng)前對(duì)象(this)public synchronized void add(int value) { … }同一對(duì)象的多個(gè)同步實(shí)例方法,同一時(shí)刻僅一個(gè)線程可執(zhí)行
靜態(tài)方法同步當(dāng)前類的Class對(duì)象(全局唯一)public static synchronized void add(int value) { … }同一類的所有靜態(tài)同步方法,同一時(shí)刻僅一個(gè)線程可執(zhí)行
實(shí)例方法中同步塊自定義對(duì)象(常用this)synchronized(this) { this.count += value; }縮小同步范圍,僅保護(hù)臨界區(qū),提升性能
靜態(tài)方法中同步塊當(dāng)前類的Class對(duì)象synchronized(MyClass.class) { … }與靜態(tài)同步方法鎖對(duì)象一致,可靈活控制同步范圍

2. 核心特性(必記)

  • 可重入性:同一線程可重復(fù)獲取同一把鎖(如同步方法調(diào)用另一個(gè)同步方法,不會(huì)死鎖)。

  • 互斥性:同一時(shí)刻,僅一個(gè)線程能持有鎖并進(jìn)入臨界區(qū)。

  • 可見(jiàn)性:線程解鎖前,對(duì)共享變量的修改會(huì)強(qiáng)制刷新到主內(nèi)存,后續(xù)加鎖線程會(huì)從主內(nèi)存讀取最新值。

  • 非公平性:線程喚醒后會(huì)隨機(jī)競(jìng)爭(zhēng)鎖,不保證請(qǐng)求順序(默認(rèn)非公平,性能更優(yōu))。

七、線程間通信(重點(diǎn):wait/notify/notifyAll)

線程間通信的核心是“協(xié)作”(如生產(chǎn)者-消費(fèi)者模型),常用方式:共享對(duì)象通信、忙等待、wait/notify/notifyAll(推薦)。

1. 共享對(duì)象通信(基礎(chǔ))

通過(guò)共享對(duì)象的成員變量傳遞信號(hào)(需配合同步,避免競(jìng)態(tài)條件)。例如:線程A在同步塊中設(shè)置hasDataToProcess = true,線程B在同步塊中讀取該變量。

2. 忙等待(不推薦)

線程B循環(huán)等待信號(hào),浪費(fèi)CPU資源(空閑時(shí)也占用CPU):

while(!sharedSignal.hasDataToProcess()){
    // 空循環(huán),忙等待,浪費(fèi)CPU
}

3. wait()、notify()、notifyAll()(核心,補(bǔ)全細(xì)節(jié))

強(qiáng)制規(guī)則(違反拋IllegalMonitorStateException)

必須在synchronized同步塊/方法中調(diào)用,且調(diào)用對(duì)象必須是“當(dāng)前持有鎖的對(duì)象”(即同步塊的鎖對(duì)象)。

核心機(jī)制(易混淆點(diǎn))

  • wait():線程釋放持有的鎖,進(jìn)入該鎖的等待隊(duì)列,變?yōu)榉沁\(yùn)行狀態(tài),直到被notify()/notifyAll()喚醒。

  • notify():隨機(jī)喚醒等待隊(duì)列中的一個(gè)線程(喚醒后需重新競(jìng)爭(zhēng)鎖,才能進(jìn)入臨界區(qū))。

  • notifyAll():?jiǎn)拘训却?duì)列中的所有線程(所有線程競(jìng)爭(zhēng)鎖,依次進(jìn)入臨界區(qū))。

關(guān)鍵疑問(wèn)解答(筆記補(bǔ)充)

問(wèn):等待線程持有鎖,會(huì)阻塞喚醒線程進(jìn)入同步塊嗎?

答:不會(huì)。線程調(diào)用wait()后,會(huì)立即釋放鎖,允許其他線程(包括喚醒線程)獲取鎖并進(jìn)入同步塊;喚醒線程執(zhí)行完同步塊、釋放鎖后,被喚醒的線程才會(huì)競(jìng)爭(zhēng)鎖,成功后退出wait()。

4. 常見(jiàn)問(wèn)題與解決方案(必記)

問(wèn)題原因解決方案
丟失信號(hào)notify()先于wait()執(zhí)行,信號(hào)未保存,等待線程錯(cuò)過(guò)喚醒用成員變量保存信號(hào)(如boolean wasSignalled),喚醒時(shí)置為true,等待時(shí)檢查該變量
假喚醒線程被喚醒但未收到有效信號(hào)(JVM底層機(jī)制)用while循環(huán)檢查信號(hào)(而非if),即“自旋鎖”:while(!wasSignalled) { wait(); }
意外喚醒用常量字符串、全局對(duì)象作為鎖,JVM會(huì)復(fù)用該對(duì)象,導(dǎo)致跨實(shí)例喚醒使用唯一鎖對(duì)象(如new Object()),避免使用""、Class對(duì)象等全局共享對(duì)象

正確實(shí)現(xiàn)示例(避免所有問(wèn)題)

public class MyWaitNotify {
    private final Object monitor = new Object(); // 唯一鎖對(duì)象
    private boolean wasSignalled = false; // 保存信號(hào),避免丟失

    // 等待信號(hào)
    public void doWait() throws InterruptedException {
        synchronized (monitor) {
            while (!wasSignalled) { // while循環(huán),防止假喚醒
                monitor.wait();
            }
            wasSignalled = false; // 清除信號(hào),準(zhǔn)備下次等待
        }
    }

    // 發(fā)送信號(hào)
    public void doNotify() {
        synchronized (monitor) {
            wasSignalled = true; // 保存信號(hào)
            monitor.notify(); // 喚醒等待線程
        }
    }
}

八、死鎖(核心:原因與避免)

1. 定義

兩個(gè)或多個(gè)線程互相持有對(duì)方需要的鎖,且永久阻塞,無(wú)法繼續(xù)執(zhí)行(線程“互相僵持”)。

2. 典型場(chǎng)景(必記)

  • 基礎(chǔ)場(chǎng)景:線程1鎖A→等B,線程2鎖B→等A,互相阻塞。

  • 代碼場(chǎng)景(TreeNode示例):線程1調(diào)用parent.addChild(child)(鎖parent),線程2調(diào)用child.setParent(parent)(鎖child),后續(xù)線程1需鎖child、線程2需鎖parent,導(dǎo)致死鎖。

  • 數(shù)據(jù)庫(kù)場(chǎng)景:多個(gè)事務(wù)更新相同記錄,順序相反(事務(wù)1鎖記錄1→等記錄2,事務(wù)2鎖記錄2→等記錄1)。

3. 死鎖產(chǎn)生的4個(gè)必要條件(缺一不可)

  • 互斥:鎖資源只能被一個(gè)線程持有。

  • 持有并等待:線程持有一個(gè)鎖,同時(shí)等待另一個(gè)鎖。

  • 不可剝奪:線程持有鎖時(shí),不能被其他線程強(qiáng)制剝奪。

  • 循環(huán)等待:多個(gè)線程形成“互相等待鎖”的循環(huán)鏈。

4. 避免死鎖的3種核心策略(重點(diǎn))

策略1:固定加鎖順序(最常用、最易實(shí)現(xiàn))

所有線程按相同順序獲取鎖(如先鎖A、再鎖B),打破“循環(huán)等待”條件。

策略2:加鎖時(shí)限

嘗試獲取鎖時(shí)設(shè)置超時(shí)時(shí)間(如用Lock.tryLock(long timeout, TimeUnit unit)),超時(shí)則釋放已持有鎖、回退,等待隨機(jī)時(shí)間后重試,打破“持有并等待”條件。

策略3:死鎖檢測(cè)

適用于無(wú)法固定加鎖順序、超時(shí)不可行的場(chǎng)景:

  • 用數(shù)據(jù)結(jié)構(gòu)(如Map、有向圖)記錄線程持有/請(qǐng)求的鎖。

  • 線程請(qǐng)求鎖失敗時(shí),遍歷鎖關(guān)系圖,檢測(cè)是否存在循環(huán)(死鎖)。

  • 檢測(cè)到死鎖后,釋放所有鎖、回退重試,或按優(yōu)先級(jí)讓部分線程回退。

九、饑餓與公平性

1. 核心概念

  • 饑餓:線程長(zhǎng)期得不到CPU運(yùn)行時(shí)間或鎖資源,最終“饑餓致死”(如低優(yōu)先級(jí)線程被高優(yōu)先級(jí)線程長(zhǎng)期搶占CPU)。

  • 公平性:所有線程公平獲取資源(按請(qǐng)求順序獲?。?,避免饑餓。

2. Java中導(dǎo)致饑餓的3個(gè)原因

  • 高優(yōu)先級(jí)線程吞噬低優(yōu)先級(jí)線程的CPU時(shí)間(Java優(yōu)先級(jí)1-10,優(yōu)先級(jí)高的線程被調(diào)度概率高)。

  • 線程永久阻塞在同步塊外(非公平鎖下,新線程可能持續(xù)搶占鎖,老線程一直等待)。

  • 線程等待一個(gè)永久無(wú)法完成的對(duì)象(如等待一個(gè)不會(huì)被notify()的對(duì)象)。

3. 實(shí)現(xiàn)公平性的方案

用Lock鎖替代synchronized(synchronized默認(rèn)非公平),自定義公平鎖或使用JUC的公平鎖(如ReentrantLock(true)):

  • 公平鎖會(huì)維護(hù)一個(gè)等待隊(duì)列,解鎖后僅喚醒隊(duì)列頭部的線程,保證請(qǐng)求順序。

  • 注意:公平鎖性能低于非公平鎖(需維護(hù)隊(duì)列、切換線程),僅在需要避免饑餓時(shí)使用。

十、Java中的鎖(進(jìn)階,補(bǔ)全筆記細(xì)節(jié))

1. 簡(jiǎn)單鎖的實(shí)現(xiàn)(理解原理)

核心是用“狀態(tài)變量+同步”控制線程訪問(wèn),示例(不可重入鎖):

public class Lock {
    private boolean isLocked = false; // 鎖狀態(tài)

    // 獲取鎖(阻塞)
    public synchronized void lock() throws InterruptedException {
        while (isLocked) { // 自旋,防止假喚醒
            wait();
        }
        isLocked = true; // 標(biāo)記為鎖定狀態(tài)
    }

    // 釋放鎖
    public synchronized void unlock() {
        isLocked = false;
        notify(); // 喚醒等待線程
    }
}

2. 鎖的可重入性(重點(diǎn))

定義

同一線程可重復(fù)獲取已持有的鎖(synchronized、ReentrantLock均支持可重入),示例:

public class ReentrantDemo {
    // 兩個(gè)同步方法,鎖對(duì)象都是this
    public synchronized void outer() { inner(); }
    public synchronized void inner() { /* 業(yè)務(wù)邏輯 */ }
}

可重入鎖的實(shí)現(xiàn)要點(diǎn)

需記錄“持有鎖的線程”和“重入次數(shù)”,修改后的可重入鎖示例:

public class ReentrantLock {
    private boolean isLocked = false;
    private Thread lockedBy = null; // 持有鎖的線程
    private int lockedCount = 0; // 重入次數(shù)

    public synchronized void lock() throws InterruptedException {
        Thread currentThread = Thread.currentThread();
        // 若鎖被占用,且不是當(dāng)前線程持有,阻塞
        while (isLocked && lockedBy != currentThread) {
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = currentThread;
    }

    public synchronized void unlock() {
        // 僅持有鎖的線程可釋放
        if (Thread.currentThread() != lockedBy) {
            throw new IllegalMonitorStateException("未持有鎖,無(wú)法釋放");
        }
        lockedCount--;
        // 重入次數(shù)為0時(shí),才釋放鎖
        if (lockedCount == 0) {
            isLocked = false;
            lockedBy = null;
            notify();
        }
    }
}

3. 關(guān)鍵注意點(diǎn):finally中調(diào)用unlock()

用Lock鎖時(shí),臨界區(qū)可能拋出異常,需在finally中釋放鎖,避免鎖泄露(鎖永久被占用):

lock.lock();
try {
    // 臨界區(qū)(可能拋出異常)
} finally {
    lock.unlock(); // 確保無(wú)論是否異常,都釋放鎖
}

十一、讀寫(xiě)鎖(ReentrantReadWriteLock)

1. 核心場(chǎng)景

適用于“讀多寫(xiě)少”的場(chǎng)景(如緩存查詢、配置讀取),解決“讀-讀互斥”的性能問(wèn)題,核心原則:

讀-讀共存、讀-寫(xiě)互斥、寫(xiě)-寫(xiě)互斥。

2. 簡(jiǎn)單實(shí)現(xiàn)(理解原理)

public class ReadWriteLock {
    private int readers = 0; // 讀線程數(shù)量
    private int writers = 0; // 寫(xiě)線程數(shù)量
    private int writeRequests = 0; // 寫(xiě)請(qǐng)求數(shù)量(優(yōu)先寫(xiě))

    // 獲取讀鎖
    public synchronized void lockRead() throws InterruptedException {
        // 有寫(xiě)線程或?qū)懻?qǐng)求,阻塞(優(yōu)先寫(xiě))
        while (writers > 0 || writeRequests > 0) {
            wait();
        }
        readers++;
    }

    // 釋放讀鎖
    public synchronized void unlockRead() {
        readers--;
        notifyAll(); // 喚醒等待的寫(xiě)線程
    }

    // 獲取寫(xiě)鎖
    public synchronized void lockWrite() throws InterruptedException {
        writeRequests++;
        // 有讀線程或?qū)懢€程,阻塞
        while (readers > 0 || writers > 0) {
            wait();
        }
        writeRequests--;
        writers++;
    }

    // 釋放寫(xiě)鎖
    public synchronized void unlockWrite() {
        writers--;
        notifyAll(); // 喚醒所有等待的讀/寫(xiě)線程
    }
}

3. 讀寫(xiě)鎖的可重入性(補(bǔ)全筆記)

上述簡(jiǎn)單實(shí)現(xiàn)不可重入,會(huì)導(dǎo)致死鎖(如持有寫(xiě)鎖的線程再次請(qǐng)求寫(xiě)鎖、持有讀鎖的線程再次請(qǐng)求讀鎖),需優(yōu)化:

  • 讀鎖重入:用Map記錄線程及讀鎖重入次數(shù),已持有讀鎖的線程可再次獲取讀鎖(無(wú)論是否有寫(xiě)請(qǐng)求)。

  • 寫(xiě)鎖重入:記錄持有寫(xiě)鎖的線程及重入次數(shù),已持有寫(xiě)鎖的線程可再次獲取寫(xiě)鎖。

  • 鎖降級(jí):持有寫(xiě)鎖的線程可直接獲取讀鎖(無(wú)需釋放寫(xiě)鎖),避免寫(xiě)鎖釋放后被其他線程搶占。

十二、信號(hào)量(Semaphore)

1. 核心作用

控制并發(fā)線程數(shù)量(如限流、連接池控制),可看作“可計(jì)數(shù)的鎖”,JUC中已提供java.util.concurrent.Semaphore,無(wú)需自定義。

2. 核心特性

  • 可計(jì)數(shù):允許同時(shí)獲取多個(gè)許可(如permits=5,可同時(shí)有5個(gè)線程獲取許可)。

  • 有上限:可設(shè)置最大許可數(shù)(如上限10,超過(guò)則阻塞)。

  • 可當(dāng)作鎖:當(dāng)permits=1時(shí),等價(jià)于非公平鎖(控制單個(gè)線程進(jìn)入臨界區(qū))。

3. 常用示例(限流)

// 上限3個(gè)線程同時(shí)執(zhí)行
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire(); // 獲取許可(阻塞,直到有空閑許可)
            // 臨界區(qū)(如接口調(diào)用、資源操作)
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 釋放許可
        }
    }).start();
}

十三、阻塞隊(duì)列(BlockingQueue)

1. 核心區(qū)別(與普通隊(duì)列)

當(dāng)隊(duì)列空時(shí),獲取元素(take())會(huì)阻塞;當(dāng)隊(duì)列滿時(shí),添加元素(put())會(huì)阻塞,無(wú)需手動(dòng)處理線程同步(內(nèi)部已實(shí)現(xiàn))。

2. 核心作用

實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型(解耦生產(chǎn)者和消費(fèi)者,平衡兩者速度),線程池底層核心組件(緩存任務(wù))。

3. 簡(jiǎn)單實(shí)現(xiàn)(理解原理)

public class BlockingQueue {
    private final List<Object> queue = new LinkedList<>();
    private final int limit; // 隊(duì)列最大容量

    public BlockingQueue(int limit) {
        this.limit = limit;
    }

    // 入隊(duì)(滿則阻塞)
    public synchronized void enqueue(Object item) throws InterruptedException {
        while (queue.size() == limit) {
            wait(); // 隊(duì)列滿,阻塞生產(chǎn)者
        }
        if (queue.size() == 0) {
            notifyAll(); // 隊(duì)列空,喚醒消費(fèi)者
        }
        queue.add(item);
    }

    // 出隊(duì)(空則阻塞)
    public synchronized Object dequeue() throws InterruptedException {
        while (queue.size() == 0) {
            wait(); // 隊(duì)列空,阻塞消費(fèi)者
        }
        if (queue.size() == limit) {
            notifyAll(); // 隊(duì)列滿,喚醒生產(chǎn)者
        }
        return queue.remove(0);
    }
}

4. JUC中的阻塞隊(duì)列(常用)

如ArrayBlockingQueue(有界)、LinkedBlockingQueue(無(wú)界/有界)、SynchronousQueue(無(wú)緩沖),直接使用即可,無(wú)需自定義。

十四、線程池(核心,補(bǔ)全筆記細(xì)節(jié))

1. 核心價(jià)值

  • 避免頻繁創(chuàng)建/銷毀線程的性能開(kāi)銷(線程創(chuàng)建需分配棧內(nèi)存、內(nèi)核對(duì)象)。

  • 控制并發(fā)線程數(shù)量,防止線程過(guò)多導(dǎo)致OOM或CPU耗盡。

  • 統(tǒng)一管理線程,便于監(jiān)控、調(diào)度、復(fù)用(如任務(wù)緩存、拒絕策略)。

2. 核心結(jié)構(gòu)

  • 工作線程集合:長(zhǎng)期存活,循環(huán)從隊(duì)列中獲取任務(wù)執(zhí)行。

  • 阻塞隊(duì)列:緩存等待執(zhí)行的任務(wù)(如生產(chǎn)者-消費(fèi)者模型中的隊(duì)列)。

  • 拒絕策略:隊(duì)列滿且線程數(shù)達(dá)到最大時(shí),處理新任務(wù)的策略(如拋異常、丟棄、阻塞)。

3. 簡(jiǎn)單實(shí)現(xiàn)(理解原理)

// 線程池核心類
public class ThreadPool {
    private final BlockingQueue<Runnable> taskQueue; // 任務(wù)隊(duì)列
    private final List<PoolThread> threads; // 工作線程集合
    private boolean isStopped = false; // 線程池狀態(tài)

    // 構(gòu)造方法:指定線程數(shù)、隊(duì)列最大容量
    public ThreadPool(int threadCount, int maxTaskCount) {
        taskQueue = new BlockingQueue<>(maxTaskCount);
        threads = new ArrayList<>(threadCount);
        // 初始化工作線程
        for (int i = 0; i < threadCount; i++) {
            threads.add(new PoolThread(taskQueue));
        }
        // 啟動(dòng)所有工作線程
        for (PoolThread thread : threads) {
            thread.start();
        }
    }

    // 提交任務(wù)
    public synchronized void execute(Runnable task) {
        if (isStopped) {
            throw new IllegalStateException("線程池已停止");
        }
        taskQueue.enqueue(task); // 任務(wù)入隊(duì)
    }

    // 停止線程池
    public synchronized void stop() {
        isStopped = true;
        // 停止所有工作線程
        for (PoolThread thread : threads) {
            thread.toStop();
        }
    }
}

// 工作線程類
class PoolThread extends Thread {
    private final BlockingQueue<Runnable> taskQueue;
    private boolean isStopped = false;

    public PoolThread(BlockingQueue<Runnable> queue) {
        this.taskQueue = queue;
    }

    @Override
    public void run() {
        // 循環(huán)獲取任務(wù),直到線程池停止
        while (!isStopped()) {
            try {
                // 從隊(duì)列獲取任務(wù)(空則阻塞)
                Runnable task = taskQueue.dequeue();
                task.run(); // 執(zhí)行任務(wù)
            } catch (Exception e) {
                // 捕獲異常,避免線程退出(線程池繼續(xù)運(yùn)行)
                e.printStackTrace();
            }
        }
    }

    // 停止當(dāng)前工作線程
    public synchronized void toStop() {
        isStopped = true;
        this.interrupt(); // 打斷阻塞在dequeue()的線程
    }

    public synchronized boolean isStopped() {
        return isStopped;
    }
}

4. JUC中的線程池(重點(diǎn))

使用java.util.concurrent.ExecutorService,推薦手動(dòng)創(chuàng)建ThreadPoolExecutor(避免Executors工具類的OOM風(fēng)險(xiǎn)),核心參數(shù):核心線程數(shù)、最大線程數(shù)、空閑線程存活時(shí)間、任務(wù)隊(duì)列、拒絕策略。

十五、CAS與原子類(無(wú)鎖編程核心)

1. CAS核心概念

CAS(Compare and Swap,比較并替換):一種無(wú)鎖原子操作,底層由CPU指令(如cmpxchg)保證原子性,核心邏輯:

  • 傳入3個(gè)參數(shù):內(nèi)存地址V、期望值A(chǔ)、新值B。

  • 比較V的值與A:若相等,將V的值替換為B;若不相等,不做操作。

  • 返回操作結(jié)果(是否替換成功)。

2. 核心優(yōu)點(diǎn)

無(wú)鎖、無(wú)線程上下文切換開(kāi)銷、無(wú)死鎖風(fēng)險(xiǎn),性能優(yōu)于synchronized(高并發(fā)、低沖突場(chǎng)景)。

3. 核心問(wèn)題與解決方案

問(wèn)題原因解決方案
ABA問(wèn)題V的值從A→B→A,CAS認(rèn)為未修改,導(dǎo)致錯(cuò)誤替換用AtomicStampedReference(加版本號(hào))
自旋消耗CPU高并發(fā)下,CAS多次失敗,循環(huán)重試消耗CPU限制自旋次數(shù),或搭配鎖使用
只能保證單個(gè)變量原子性CAS僅能操作單個(gè)變量,無(wú)法保證多個(gè)變量的復(fù)合操作原子性用AtomicReference包裝多個(gè)變量,或使用鎖

4. JUC原子類(常用)

  • 基本類型:AtomicInteger、AtomicLong、AtomicBoolean(如計(jì)數(shù)器、狀態(tài)標(biāo)記)。

  • 引用類型:AtomicReference、AtomicStampedReference(解決ABA問(wèn)題)。

  • 數(shù)組類型:AtomicIntegerArray、AtomicLongArray(原子操作數(shù)組元素)。

十六、同步器核心思想(查漏補(bǔ)缺)

鎖、信號(hào)量、阻塞隊(duì)列等同步器,底層設(shè)計(jì)邏輯一致,均包含4個(gè)核心部分:

  • 狀態(tài):控制線程訪問(wèn)權(quán)限(如Lock的isLocked、Semaphore的permits)。

  • 訪問(wèn)條件:基于狀態(tài)判斷線程是否可訪問(wèn)(如while循環(huán)檢查,防止假喚醒)。

  • 狀態(tài)變化:線程獲取/釋放資源時(shí),修改同步器狀態(tài)(如Lock的isLocked=true/false)。

  • 通知策略:狀態(tài)變化后,通知等待線程(notify()/notifyAll(),如釋放鎖后喚醒等待線程)。

同步器的兩種核心方法

  • Test-and-Set(測(cè)試-設(shè)置):原子操作,先檢查訪問(wèn)條件,滿足則修改狀態(tài)(如CAS、lock())。

  • Set(設(shè)置):僅修改狀態(tài),不檢查條件(如unlock(),持有鎖的線程可直接釋放)。

十七、阻塞算法與非阻塞算法(補(bǔ)全筆記)

1. 核心區(qū)別

類型核心邏輯優(yōu)點(diǎn)缺點(diǎn)示例
阻塞算法獲取不到資源時(shí),線程掛起,直到資源可用實(shí)現(xiàn)簡(jiǎn)單,無(wú)CPU自旋消耗線程切換開(kāi)銷大,可能死鎖synchronized、Lock
非阻塞算法獲取不到資源時(shí),不掛起,直接返回或重試無(wú)線程切換開(kāi)銷,無(wú)死鎖實(shí)現(xiàn)復(fù)雜,高沖突下自旋消耗CPUCAS、原子類

2. 樂(lè)觀鎖(非阻塞算法核心)

核心思想:樂(lè)觀假設(shè)“無(wú)并發(fā)沖突”,線程先拷貝共享資源、修改,再通過(guò)CAS將修改寫(xiě)回主內(nèi)存,沖突則重試。

  • 適用場(chǎng)景:低并發(fā)、低沖突(如緩存更新),避免鎖的開(kāi)銷。

  • 注意:高沖突場(chǎng)景下,重試頻繁,性能低于阻塞算法。

十八、高頻面試重點(diǎn)(濃縮必記)

  1. 線程啟動(dòng)必須用start(),調(diào)用run()僅為普通方法調(diào)用,不啟動(dòng)新線程。

  2. 線程安全三要素:原子性(CAS、鎖)、可見(jiàn)性(synchronized、volatile)、有序性(synchronized、volatile)。

  3. synchronized與Lock的區(qū)別:Lock可中斷、可超時(shí)、可公平/非公平,synchronized自動(dòng)釋放鎖、可重入、簡(jiǎn)單易用。

  4. 死鎖產(chǎn)生的4個(gè)條件及避免方法(固定加鎖順序最常用)。

  5. CAS的原理、優(yōu)點(diǎn)、ABA問(wèn)題及解決方案。

  6. 線程池的核心價(jià)值、結(jié)構(gòu),手動(dòng)創(chuàng)建ThreadPoolExecutor的原因(避免Executors的OOM)。

  7. 讀寫(xiě)鎖的核心原則(讀-讀共存、讀-寫(xiě)/寫(xiě)-寫(xiě)互斥),適用場(chǎng)景(讀多寫(xiě)少)。

  8. wait()與sleep()的區(qū)別:wait()釋放鎖、需在同步塊中,sleep()不釋放鎖、可在任意位置。

總結(jié) 

到此這篇關(guān)于Java多線程與并發(fā)的文章就介紹到這了,更多相關(guān)Java多線程與并發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot配置允許跨域訪問(wèn)代碼實(shí)例

    springboot配置允許跨域訪問(wèn)代碼實(shí)例

    這篇文章主要介紹了springboot配置允許跨域訪問(wèn)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • spring boot啟動(dòng)時(shí)mybatis報(bào)循環(huán)依賴的錯(cuò)誤(推薦)

    spring boot啟動(dòng)時(shí)mybatis報(bào)循環(huán)依賴的錯(cuò)誤(推薦)

    今天小編抽時(shí)間給大家分享spring boot啟動(dòng)時(shí)mybatis報(bào)循環(huán)依賴的錯(cuò)誤,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2017-12-12
  • eclipse/intellij idea 查看java源碼和注釋方法

    eclipse/intellij idea 查看java源碼和注釋方法

    下面小編就為大家?guī)?lái)一篇eclipse/intellij idea 查看java源碼和注釋方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • Spring?Boot在開(kāi)發(fā)過(guò)程中常用IDEA插件

    Spring?Boot在開(kāi)發(fā)過(guò)程中常用IDEA插件

    這篇文章主要為大家介紹了Spring?Boot在開(kāi)發(fā)過(guò)程中常用IDEA插件,幫助大家提高開(kāi)發(fā)工作效率,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • java 線性表接口的實(shí)例詳解

    java 線性表接口的實(shí)例詳解

    這篇文章主要介紹了java 線性表接口的實(shí)現(xiàn)實(shí)例詳解的相關(guān)資料,希望通過(guò)本能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Java Swing界面美化與JPanel優(yōu)化的完全指南

    Java Swing界面美化與JPanel優(yōu)化的完全指南

    ava Swing 作為經(jīng)典的桌面應(yīng)用框架,功能強(qiáng)大但界面設(shè)計(jì)往往停留在上個(gè)時(shí)代,本文系統(tǒng)介紹如何使用 FlatLaf 等現(xiàn)代化工具美化 Swing 界面,并提供 JPanel 布局優(yōu)化的完整解決方案,讓你的桌面應(yīng)用煥然一新,需要的朋友可以參考下
    2026-02-02
  • 基于Java回顧之JDBC的使用詳解

    基于Java回顧之JDBC的使用詳解

    本篇文章是對(duì)Java中JDBC的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • windows系統(tǒng)上如何進(jìn)行maven安裝和配置方式

    windows系統(tǒng)上如何進(jìn)行maven安裝和配置方式

    這篇文章主要介紹了windows系統(tǒng)上如何進(jìn)行maven安裝和配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Java從控制臺(tái)接受輸入字符的簡(jiǎn)單方法

    Java從控制臺(tái)接受輸入字符的簡(jiǎn)單方法

    這篇文章主要介紹了Java從控制臺(tái)接受輸入字符的簡(jiǎn)單方法,需要的朋友可以參考下
    2014-02-02
  • springboot頁(yè)面國(guó)際化配置指南

    springboot頁(yè)面國(guó)際化配置指南

    聽(tīng)起來(lái)高大上的國(guó)際化,起始就是在利用瀏覽器語(yǔ)言,或者頁(yè)面中的中英文切換,將頁(yè)面的文字在其他語(yǔ)言和中文進(jìn)行切換,這篇文章主要給大家介紹了關(guān)于springboot頁(yè)面國(guó)際化配置的相關(guān)資料,需要的朋友可以參考下
    2022-03-03

最新評(píng)論

云浮市| 柏乡县| 怀远县| 当阳市| 长沙县| 尚志市| 萨迦县| 宜兴市| 沧源| 福清市| 荃湾区| 伽师县| 合肥市| 大关县| 铅山县| 固原市| 洪泽县| 谷城县| 财经| 吉首市| 海淀区| 亚东县| 新干县| 佛冈县| 开鲁县| 贵溪市| 江都市| 曲周县| 甘肃省| 池州市| 阳江市| 读书| 洛浦县| 齐齐哈尔市| 科尔| 昌黎县| 仁布县| 德钦县| 泸西县| 名山县| 郎溪县|