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

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

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

線程同步的方式有哪些?

線程同步

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

線程同步的方式有哪些?

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

死鎖

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

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

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

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

如何解決死鎖?

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

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

死鎖如何恢復?

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

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

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

當數(shù)據(jù)庫發(fā)生死鎖的時候,會報出來如下的錯誤:

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ù)庫操作中如何避免死鎖?

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

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

多線程編排

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

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

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

單個任務

runAsync:無返回值

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

supplyAsync:有返回值

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

指定線程池

因為CompletableFuture默認底層是使用的ForkJoinPool.commonPool(),但是也是可以自定義線程池,配置線程的一些指定信息。

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

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

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

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

CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }).thenRunAsync(() -> {
            System.out.println("after Hello World");
        });
組合多個任務編排
  1. 串行組合(thenCompose),可以將前一個任務的結(jié)果傳遞給下一個任務(鏈式依賴)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
System.out.println(future.get()); // 輸出: Hello World
  1. 并行組合(thenCombine),將兩個獨立任務的結(jié)果進行合并
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. 多任務并行(allOf / anyOf)
  • allOf:等待所有任務完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
    CompletableFuture.runAsync(() -> System.out.println("Task 1")),
    CompletableFuture.runAsync(() -> System.out.println("Task 2"))
);
allFutures.get(); // 等待所有任務完成
  • anyOf:任一任務完成即觸發(fā)
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(
    CompletableFuture.supplyAsync(() -> "Task 1"),
    CompletableFuture.supplyAsync(() -> "Task 2")
);
System.out.println(anyFuture.get()); // 輸出: Task 1 或 Task 2(取決于哪個先完成)
任務編排異常處理
  1. 捕獲異常(exceptionally),在任務拋出異常時提供默認信息。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("失敗");
    return "成功";
}).exceptionally(ex -> {
    System.out.println("異常處理: " + ex.getMessage());
    return "默認值";
});
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 "默認值";
    }
    return result;
});
  • whenComplete:無論成功或失敗均執(zhí)行(不可中斷)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("失敗");
    return "成功";
}).whenComplete((result, ex) -> {
    if (ex != null) System.out.println("任務失敗");
    else System.out.println("任務成功: " + result);
});

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

相關(guān)文章

最新評論

广东省| 集贤县| 伊吾县| 江北区| 如皋市| 丰都县| 陕西省| 海兴县| 芜湖市| 营口市| 怀柔区| 尖扎县| 淳安县| 龙泉市| 云林县| 获嘉县| 延寿县| 同仁县| 顺昌县| 汽车| 巩义市| 屏南县| 霍邱县| 石景山区| 巴青县| 德安县| 镇雄县| 凤翔县| 海淀区| 济南市| 黄石市| 揭阳市| 林口县| 固阳县| 股票| 漾濞| 沙河市| 崇义县| 金湖县| 望江县| 山阴县|