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

Java并發(fā)之線程同步、死鎖、多線程編排全面解析

 更新時(shí)間:2025年09月15日 08:54:16   作者:紀(jì)莫  
本文系統(tǒng)講解了Java多線程同步機(jī)制、死鎖原理及解決方法,以及CompletableFuture實(shí)現(xiàn)異步編排的核心功能,涵蓋鎖類型、并發(fā)工具、資源管理策略等內(nèi)容,感興趣的朋友跟隨小編一起看看吧

線程同步的方式有哪些?

線程同步

線程同步,是多線程編程中的一種機(jī)制,用于協(xié)調(diào)多個(gè)線程的執(zhí)行順序,確保它們?cè)诠蚕碣Y源或關(guān)鍵操作上按照預(yù)定的規(guī)則運(yùn)行,避免因并發(fā)訪問導(dǎo)致的數(shù)據(jù)不一致、競(jìng)態(tài)條件(Race Condition)等問題。

線程同步的方式有哪些?

  1. synchronized 關(guān)鍵字,通過 JVM 內(nèi)置的鎖機(jī)制實(shí)現(xiàn)線程同步,確保同一時(shí)刻只有一個(gè)線程訪問共享資源。既可以修飾實(shí)例方法也可以修飾靜態(tài)方法,也可以鎖代碼塊和鎖住某個(gè)具體的實(shí)例對(duì)象
public synchronized void method() { ... } // 實(shí)例方法鎖(this)
public static synchronized void method() { ... } // 類方法鎖(Class 對(duì)象)
// 鎖實(shí)例對(duì)象
synchronized (lockObject) {
    // 同步代碼塊
}
  1. ReentrantLock 基于 java.util.concurrent.locks.Lock 接口實(shí)現(xiàn)的可重入互斥鎖,需顯式調(diào)用 lock()unlock()進(jìn)行加鎖和解鎖。
    支持公平鎖、可中斷鎖、超時(shí)鎖以及多條件變量(Condition),相比 synchronized 提供了更高的靈活性。
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // 同步代碼
} finally {
    lock.unlock();
}
  1. Semaphore(信號(hào)量),允許多個(gè)線程同時(shí)訪問資源,但是限制訪問線程的數(shù)量。
Semaphore semaphore = new Semaphore(3); // 初始許可數(shù)為3
semaphore.acquire(); // 獲取許可
try {
    // 同步代碼
} finally {
    semaphore.release(); // 釋放許可
}
  1. CountDownLatch,允許多個(gè)線程等待其他線程執(zhí)行完畢之后再執(zhí)行,用于線程間的協(xié)作。
public class LatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 3;
        CountDownLatch latch = new CountDownLatch(threadCount);
        for (int i = 1; i <= threadCount; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 初始化完成");
                latch.countDown(); // 子線程完成,計(jì)數(shù)器減 1
            }, "線程-" + i).start();
        }
        latch.await(); // 主線程等待所有子線程完成
        System.out.println("所有子線程完成,主線程繼續(xù)執(zhí)行");
    }
}
  1. CyclicBarrier,多個(gè)線程互相等待,所有線程都到到屏障點(diǎn)后,再繼續(xù)執(zhí)行。線程計(jì)數(shù)器可重置。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierExample {
    // 總和變量(線程安全)
    private static int sum = 0;
    // 線程池
    private static final ExecutorService executor = Executors.newFixedThreadPool(5);
    public static void main(String[] args) {
        // 定義需要等待的線程數(shù)量(5個(gè))
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
            // 所有線程到達(dá)屏障后執(zhí)行的回調(diào)(匯總結(jié)果)
            System.out.println("所有線程已完成計(jì)算,總和為: " + sum);
        });
        // 啟動(dòng)5個(gè)線程
        for (int i = 0; i < 5; i++) {
            executor.execute(() -> {
                try {
                    // 模擬線程計(jì)算
                    int value = (int) (Math.random() * 100);
                    System.out.println(Thread.currentThread().getName() + " 計(jì)算值: " + value);
                    // 將計(jì)算結(jié)果累加到總和中
                    sum += value;
                    // 調(diào)用await()等待其他線程到達(dá)屏障
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        // 關(guān)閉線程池
        executor.shutdown();
    }
}
  1. Phaser,和CyclicBarrier類似,但是支持更靈活的屏障操作,適用于復(fù)雜多階段任務(wù),支持動(dòng)態(tài)注冊(cè)/注銷參與者,并可控制各參與者的階段進(jìn)度,并可以控制各個(gè)參與者的到達(dá)和離開。
Phaser phaser = new Phaser(1); // 初始參與線程
phaser.bulkRegister(3);        // 動(dòng)態(tài)注冊(cè)3個(gè)工作線程
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        for (int phase = 0; phase < 2; phase++) {
            phaser.arriveAndAwaitAdvance(); // 階段1:等待所有線程完成階段1
            // 執(zhí)行階段2任務(wù)
        }
        phaser.arriveAndDeregister(); // 完成并注銷
    }).start();
}
// 主線程等待所有線程完成
phaser.arriveAndAwaitAdvance();
  1. 其他,另外還有volatile,這種能保證可見性和有序性,但不能保證原子性的關(guān)鍵字。以及基于CAS實(shí)現(xiàn)的Atomic 類(無(wú)鎖同步),但是僅適用于簡(jiǎn)單數(shù)據(jù)類型和部分操作(如 getAndAdd)。

死鎖

死鎖,通常是指在兩個(gè)或多個(gè)進(jìn)程(或線程、事務(wù))在執(zhí)行過程中,因爭(zhēng)奪資源而陷入相互等待的狀態(tài),導(dǎo)致所有進(jìn)程都無(wú)法繼續(xù)執(zhí)行。

什么情況下會(huì)產(chǎn)生死鎖?

產(chǎn)生死鎖的四個(gè)必要條件

  • 互斥(Mutual Exclusion),一個(gè)資源只能被一個(gè)進(jìn)程占用,其他進(jìn)程必須等待其釋放。
  • 占有并等待(Hold and Wait),進(jìn)程在持有資源的同時(shí),申請(qǐng)新的資源。
  • 不可剝奪(No Preemption),資源只能由持有它的進(jìn)程主動(dòng)釋放,不能被強(qiáng)制剝奪。
  • 循環(huán)等待(Circular Wait),存在一個(gè)進(jìn)程環(huán),每個(gè)進(jìn)程都在等待下一個(gè)進(jìn)程所持有的資源。

如何解決死鎖?

上面我們已經(jīng)知道產(chǎn)生死鎖有四個(gè)必要條件,那解決死鎖,只需要破壞死鎖的這些必要條件即可。
一般從以下幾方面入手即可:

  • 破壞“占有并等待”條件
  • 進(jìn)程或線程一次性申請(qǐng)所需的所有資源,否則不分配任何資源。(可能導(dǎo)致資源利用率低,進(jìn)程長(zhǎng)期等待資源
  • 進(jìn)程或線程申請(qǐng)資源時(shí),必須釋放已持有的所有資源。(可能導(dǎo)致頻繁的資源釋放和重新申請(qǐng),增加系統(tǒng)開銷
  • 破壞“不可剝奪”條件,允許系統(tǒng)強(qiáng)制回收資源。(可能中斷進(jìn)程的正常執(zhí)行,導(dǎo)致數(shù)據(jù)不一致
  • 破壞“循環(huán)等待”條件,要求進(jìn)程或線程按順序申請(qǐng)資源。保證多個(gè)進(jìn)程(線程)的執(zhí)行順序相同即可避免循環(huán)等待。這是最常用的解決死鎖的方法。
  • 例如:事務(wù)1的執(zhí)行順序是:A->B->C,事務(wù)2的執(zhí)行順序是:C->D->A,這種情況下就容易產(chǎn)生死鎖。因?yàn)槭聞?wù)1占用了A,等待C,但是事務(wù)2占用了C但是等待A。因此只需要把事務(wù)2的執(zhí)行順序改成:A->D->C,這樣事務(wù)2在執(zhí)行時(shí),會(huì)發(fā)現(xiàn)事務(wù)1占用著A呢,因此事務(wù)會(huì)先不執(zhí)行,等待事務(wù)1釋放A。

死鎖如何恢復(fù)?

  • 回滾進(jìn)程或線程,可以執(zhí)行一個(gè)或多個(gè)進(jìn)程(或線程)回滾到安全狀態(tài),釋放資源。一般回滾時(shí),要遵循按優(yōu)先級(jí)選擇(優(yōu)先級(jí)低的進(jìn)程先回滾) 。按資源占用時(shí)間選擇(占用時(shí)間短的進(jìn)程先回滾)。
  • 終止進(jìn)程或線程,直接終止全部或部分死鎖進(jìn)程(或線程),釋放資源。(可能導(dǎo)致數(shù)據(jù)丟失或事務(wù)不完整)
  • 資源剝奪,從某些進(jìn)程或線程中強(qiáng)制回收資源分配給其他進(jìn)程。
  • 超時(shí)機(jī)制,為進(jìn)程或線程設(shè)置等待資源的超時(shí)時(shí)間,若超時(shí)則自動(dòng)放棄請(qǐng)求并釋放已占資源。

數(shù)據(jù)庫(kù)中的死鎖

在操作數(shù)據(jù)庫(kù)時(shí),如果有多個(gè)事務(wù)并發(fā)執(zhí)行,也是可能發(fā)生死鎖的。當(dāng)事務(wù)1持有資源A的鎖,但是嘗試獲取資源B的鎖,而事務(wù)2持有資源B的鎖,嘗試獲取資源A的鎖的時(shí)候,這時(shí)候就會(huì)發(fā)生死鎖的情況。

當(dāng)數(shù)據(jù)庫(kù)發(fā)生死鎖的時(shí)候,會(huì)報(bào)出來如下的錯(cuò)誤:

Error updating database. Cause: ERR-CODE: [TDDL-4614][ERR EXECUTE ON MYSQL]
Deadlock found when trying to get lock;
The error occurred while setting parameters### SQL:
update test_table set updated=now(),type_state = ? where test_num = 123

數(shù)據(jù)庫(kù)操作中如何避免死鎖?

一般對(duì)于數(shù)據(jù)庫(kù)的死鎖,主要是避免發(fā)生并發(fā)更新同一資源的操作?;蛘呖梢钥紤]保證操作的順序,比如多個(gè)事務(wù)都是先操作資源A、再操作資源B,這樣就能有效的避免死鎖。

還有一些其他優(yōu)化措施:
減少事務(wù)持有鎖的時(shí)間:盡快提交或回滾事務(wù)。
鎖粒度控制:使用行級(jí)鎖而非表級(jí)鎖,減少資源競(jìng)爭(zhēng)。
避免嵌套事務(wù):減少循環(huán)等待的可能性。

多線程編排

在 Java 中,多線程的編排可以通過多種方式實(shí)現(xiàn),主要涉及 線程池、同步機(jī)制、并發(fā)工具類 以及 任務(wù)協(xié)調(diào)工具(如 Future、CompletableFuture)等。

CompletableFuture怎么實(shí)現(xiàn)多線程異步編排?

CompletableFuture,提供了非常強(qiáng)大的Future的擴(kuò)展功能,可以幫助我們簡(jiǎn)化異步編程的復(fù)雜性,提供了函數(shù)式編程的能力,可以通過回調(diào)的方式處理計(jì)算結(jié)果,并且提供了轉(zhuǎn)換和組合CompletableFuture的方法。
我在【上一篇文章】提過CompletableFuture底層就是用ForkJoinPool來實(shí)現(xiàn),那么CompletableFuture如何使用來實(shí)現(xiàn)多線程任務(wù)編排的呢?

單個(gè)任務(wù)

runAsync:無(wú)返回值

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    System.out.println("無(wú)返回值任務(wù)執(zhí)行中");
});

supplyAsync:有返回值

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "異步任務(wù)結(jié)果";
});
System.out.println(future.get()); // 輸出: 異步任務(wù)結(jié)果

指定線程池

因?yàn)?code>CompletableFuture默認(rèn)底層是使用的ForkJoinPool.commonPool(),但是也是可以自定義線程池,配置線程的一些指定信息。

ExecutorService executor = Executors.newFixedThreadPool(2);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "自定義線程池任務(wù)";
}, executor);
兩個(gè)任務(wù)編排

thenApplyAsync:能接收上一次的執(zhí)行結(jié)果,還可以有返回值

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
    .thenApplyAsync(result -> result + " World");// 運(yùn)行結(jié)果 Hello World

thenRunAsync:不能接收上一次的執(zhí)行結(jié)果,并且也沒返回值

CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }).thenRunAsync(() -> {
            System.out.println("after Hello World");
        });
組合多個(gè)任務(wù)編排
  1. 串行組合(thenCompose),可以將前一個(gè)任務(wù)的結(jié)果傳遞給下一個(gè)任務(wù)(鏈?zhǔn)揭蕾嚕?/li>
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
System.out.println(future.get()); // 輸出: Hello World
  1. 并行組合(thenCombine),將兩個(gè)獨(dú)立任務(wù)的結(jié)果進(jìn)行合并
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2)
       .thenAccept(System.out::println); // 輸出: Hello World
  1. 多任務(wù)并行(allOf / anyOf)
  • allOf:等待所有任務(wù)完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
    CompletableFuture.runAsync(() -> System.out.println("Task 1")),
    CompletableFuture.runAsync(() -> System.out.println("Task 2"))
);
allFutures.get(); // 等待所有任務(wù)完成
  • anyOf:任一任務(wù)完成即觸發(fā)
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(
    CompletableFuture.supplyAsync(() -> "Task 1"),
    CompletableFuture.supplyAsync(() -> "Task 2")
);
System.out.println(anyFuture.get()); // 輸出: Task 1 或 Task 2(取決于哪個(gè)先完成)
任務(wù)編排異常處理
  1. 捕獲異常(exceptionally),在任務(wù)拋出異常時(shí)提供默認(rèn)信息。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("失敗");
    return "成功";
}).exceptionally(ex -> {
    System.out.println("異常處理: " + ex.getMessage());
    return "默認(rèn)值";
});
System.out.println(future.get());
  1. 全局處理(handle / whenComplete
  • handle:處理異常并返回新結(jié)果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("失敗");
    return "成功";
}).handle((result, ex) -> {
    if (ex != null) {
        System.out.println("異常處理: " + ex.getMessage());
        return "默認(rèn)值";
    }
    return result;
});
  • whenComplete:無(wú)論成功或失敗均執(zhí)行(不可中斷)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("失敗");
    return "成功";
}).whenComplete((result, ex) -> {
    if (ex != null) System.out.println("任務(wù)失敗");
    else System.out.println("任務(wù)成功: " + result);
});

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

相關(guān)文章

  • JAVA實(shí)現(xiàn)監(jiān)測(cè)tomcat是否宕機(jī)及控制重啟的方法

    JAVA實(shí)現(xiàn)監(jiān)測(cè)tomcat是否宕機(jī)及控制重啟的方法

    這篇文章主要介紹了JAVA實(shí)現(xiàn)監(jiān)測(cè)tomcat是否宕機(jī)及控制重啟的方法,可實(shí)現(xiàn)有效的檢測(cè)及控制tomcat服務(wù)器運(yùn)行,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • Java高級(jí)應(yīng)用之斗地主游戲

    Java高級(jí)應(yīng)用之斗地主游戲

    這篇文章主要為大家詳細(xì)介紹了Java高級(jí)應(yīng)用之斗地主游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • SpringBoot錯(cuò)誤提示400狀態(tài)問題

    SpringBoot錯(cuò)誤提示400狀態(tài)問題

    這篇文章主要介紹了SpringBoot錯(cuò)誤提示400狀態(tài)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Spring Cloud基于zuul實(shí)現(xiàn)網(wǎng)關(guān)過程解析

    Spring Cloud基于zuul實(shí)現(xiàn)網(wǎng)關(guān)過程解析

    這篇文章主要介紹了Spring Cloud基于zuul實(shí)現(xiàn)網(wǎng)關(guān)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • SpringBoot創(chuàng)建RSocket服務(wù)器的全過程記錄

    SpringBoot創(chuàng)建RSocket服務(wù)器的全過程記錄

    RSocket應(yīng)用層協(xié)議支持 Reactive Streams語(yǔ)義, 例如:用RSocket作為HTTP的一種替代方案。這篇文章主要給大家介紹了關(guān)于SpringBoot創(chuàng)建RSocket服務(wù)器的相關(guān)資料,需要的朋友可以參考下
    2021-05-05
  • springboot使用mybatis開啟事務(wù)回滾

    springboot使用mybatis開啟事務(wù)回滾

    本文主要介紹了springboot使用mybatis開啟事務(wù)回滾,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • IntelliJ中高效重構(gòu)的10個(gè)快捷方式詳解

    IntelliJ中高效重構(gòu)的10個(gè)快捷方式詳解

    這篇文章主要為大家介紹了IntelliJ中高效重構(gòu)的10個(gè)快捷方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案

    Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案

    這篇文章主要介紹了Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringBoot如何注冊(cè)Servlet、Filter、Listener的幾種方式

    SpringBoot如何注冊(cè)Servlet、Filter、Listener的幾種方式

    在Servlet 3.0之前都是使用web.xml文件進(jìn)行配置,這篇文章主要介紹了SpringBoot如何注冊(cè)Servlet、Filter、Listener的幾種方式,在Servlet 3.0之前都是使用web.xml文件進(jìn)行配置,
    2018-10-10
  • 在MyBatis的XML映射文件中<trim>元素所有場(chǎng)景下的完整使用示例代碼

    在MyBatis的XML映射文件中<trim>元素所有場(chǎng)景下的完整使用示例代碼

    在MyBatis的XML映射文件中,<trim>元素用于動(dòng)態(tài)添加SQL語(yǔ)句的一部分,處理前綴、后綴及多余的逗號(hào)或連接符,示例展示了如何在UPDATE、SELECT、INSERT和SQL片段中使用<trim>元素,以實(shí)現(xiàn)動(dòng)態(tài)的SQL構(gòu)建,感興趣的朋友一起看看吧
    2025-01-01

最新評(píng)論