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

Java中控制多線程順序執(zhí)行的六種實(shí)現(xiàn)方案

 更新時(shí)間:2025年09月14日 14:33:58   作者:Bug改不動(dòng)了  
在多線程編程中,線程的執(zhí)行順序本質(zhì)上是不確定的,由操作系統(tǒng)調(diào)度器決定,但在某些業(yè)務(wù)場(chǎng)景中,我們需要確保線程按照特定順序執(zhí)行,所以本文介紹了Java中控制多線程順序執(zhí)行的六種實(shí)現(xiàn)方案,需要的朋友可以參考下

一、線程順序執(zhí)行的核心挑戰(zhàn)

在多線程編程中,線程的執(zhí)行順序本質(zhì)上是不確定的,由操作系統(tǒng)調(diào)度器決定。但在某些業(yè)務(wù)場(chǎng)景中,我們需要確保線程按照特定順序執(zhí)行,例如:

  1. 分階段任務(wù)處理(先初始化,再加載,最后執(zhí)行)
  2. 事件的有序處理(保證事件處理的先后順序)
  3. 資源的有序訪問(wèn)(避免競(jìng)爭(zhēng)條件)

下面介紹的6種方法都能解決這個(gè)問(wèn)題,但各有特點(diǎn)和適用場(chǎng)景。

二、6種實(shí)現(xiàn)方法詳解

方法1:join() - 簡(jiǎn)單直接的阻塞方案

實(shí)現(xiàn)原理

join()方法會(huì)使當(dāng)前線程等待目標(biāo)線程執(zhí)行完畢。通過(guò)在主線程中依次調(diào)用各個(gè)線程的join(),可以實(shí)現(xiàn)嚴(yán)格的順序執(zhí)行。

public class JoinExample {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("第一階段任務(wù)執(zhí)行");
            // 模擬任務(wù)執(zhí)行時(shí)間
            try { Thread.sleep(500); } catch (InterruptedException e) {}
        });
        
        Thread t2 = new Thread(() -> System.out.println("第二階段任務(wù)執(zhí)行"));
        Thread t3 = new Thread(() -> System.out.println("第三階段任務(wù)執(zhí)行"));
        
        try {
            System.out.println("啟動(dòng)第一階段任務(wù)");
            t1.start();
            t1.join();  // 主線程在此等待t1完成
            
            System.out.println("啟動(dòng)第二階段任務(wù)");
            t2.start();
            t2.join();  // 等待t2完成
            
            System.out.println("啟動(dòng)第三階段任務(wù)");
            t3.start();
            t3.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("任務(wù)執(zhí)行被中斷");
        }
    }
}

優(yōu)點(diǎn)

  • 實(shí)現(xiàn)簡(jiǎn)單直觀
  • 不需要額外同步工具

缺點(diǎn)

  • 會(huì)阻塞主線程
  • 不夠靈活,難以應(yīng)對(duì)復(fù)雜場(chǎng)景

適用場(chǎng)景:簡(jiǎn)單的線性任務(wù)流,且可以接受阻塞主線程的情況。

方法2:?jiǎn)尉€程線程池 - 優(yōu)雅的任務(wù)隊(duì)列方案

實(shí)現(xiàn)原理

通過(guò)Executors.newSingleThreadExecutor()創(chuàng)建單線程的線程池,自然保證任務(wù)按提交順序執(zhí)行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        
        executor.execute(() -> {
            System.out.println("準(zhǔn)備數(shù)據(jù)");
            // 模擬耗時(shí)操作
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
        });
        
        executor.execute(() -> System.out.println("處理數(shù)據(jù)"));
        executor.execute(() -> System.out.println("保存結(jié)果"));
        
        executor.shutdown();
        
        // 等待所有任務(wù)完成
        while (!executor.isTerminated()) {}
        System.out.println("所有任務(wù)已完成");
    }
}

優(yōu)點(diǎn)

  • 自動(dòng)管理線程生命周期
  • 支持任務(wù)隊(duì)列
  • 避免手動(dòng)創(chuàng)建線程

缺點(diǎn)

  • 無(wú)法靈活控制中間狀態(tài)
  • 單線程可能成為性能瓶頸

適用場(chǎng)景:需要順序執(zhí)行但可能動(dòng)態(tài)添加任務(wù)的場(chǎng)景。

方法3:CountDownLatch - 靈活的同步屏障方案

實(shí)現(xiàn)原理

CountDownLatch通過(guò)計(jì)數(shù)器實(shí)現(xiàn)線程等待,允許一個(gè)或多個(gè)線程等待其他線程完成操作。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) {
        // 第一個(gè)閘門,初始為1表示t1可以直接執(zhí)行
        CountDownLatch latch1 = new CountDownLatch(1);
        // 第二個(gè)閘門,t2需要等待
        CountDownLatch latch2 = new CountDownLatch(1);
        
        Thread t1 = new Thread(() -> {
            System.out.println("數(shù)據(jù)庫(kù)連接建立");
            latch1.countDown(); // t1完成后打開(kāi)閘門1
        });
        
        Thread t2 = new Thread(() -> {
            try {
                latch1.await(); // 等待閘門1打開(kāi)
                System.out.println("查詢用戶數(shù)據(jù)");
                latch2.countDown(); // t2完成后打開(kāi)閘門2
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        Thread t3 = new Thread(() -> {
            try {
                latch2.await(); // 等待閘門2打開(kāi)
                System.out.println("生成報(bào)表");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        // 故意打亂啟動(dòng)順序測(cè)試
        t3.start();
        t2.start();
        t1.start();
    }
}

優(yōu)點(diǎn)

  • 靈活控制多個(gè)線程的依賴關(guān)系
  • 支持一對(duì)多、多對(duì)多同步
  • 不阻塞主線程

缺點(diǎn)

  • 需要?jiǎng)?chuàng)建多個(gè)CountDownLatch對(duì)象
  • 計(jì)數(shù)器不可重置

適用場(chǎng)景:分階段任務(wù),特別是多階段有復(fù)雜依賴關(guān)系的場(chǎng)景。

方法4:ReentrantLock與Condition - 精準(zhǔn)控制的等待/通知機(jī)制

實(shí)現(xiàn)原理

ReentrantLock配合Condition提供了比synchronized更靈活的線程通信機(jī)制。每個(gè)Condition對(duì)象實(shí)質(zhì)上是一個(gè)獨(dú)立的等待隊(duì)列,可以實(shí)現(xiàn)精確的線程喚醒控制。

import java.util.concurrent.locks.*;

public class ReentrantLockConditionExample {
    // 可重入鎖
    private static Lock lock = new ReentrantLock(true); // 公平鎖
    // 三個(gè)條件變量
    private static Condition condition1 = lock.newCondition();
    private static Condition condition2 = lock.newCondition();
    private static Condition condition3 = lock.newCondition();
    // 狀態(tài)標(biāo)志
    private static volatile int flag = 1;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> task(1, 2, condition1, condition2));
        Thread t2 = new Thread(() -> task(2, 3, condition2, condition3));
        Thread t3 = new Thread(() -> task(3, 1, condition3, condition1));

        t1.start();
        t2.start();
        t3.start();

        // 模擬運(yùn)行后停止
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

    private static void task(int currentFlag, int nextFlag, 
                           Condition waitCondition, Condition signalCondition) {
        while (true) {
            lock.lock();
            try {
                // 檢查是否輪到自己執(zhí)行
                while (flag != currentFlag) {
                    waitCondition.await(); // 釋放鎖并等待
                }
                
                System.out.println("Thread " + currentFlag + " 正在執(zhí)行");
                Thread.sleep(1000); // 模擬處理時(shí)間
                
                // 更新?tīng)顟B(tài)并喚醒下一個(gè)線程
                flag = nextFlag;
                signalCondition.signal();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        }
    }
}

關(guān)鍵點(diǎn)解析

  1. 公平鎖:構(gòu)造ReentrantLock時(shí)傳入true參數(shù)創(chuàng)建公平鎖,減少線程饑餓
  2. 條件變量:每個(gè)線程有自己專屬的Condition,避免無(wú)效喚醒
  3. volatile變量:確保狀態(tài)標(biāo)志的可見(jiàn)性
  4. await/signal:精確控制線程的等待和喚醒

優(yōu)點(diǎn)

  • 最精確的線程控制能力
  • 支持公平性配置
  • 可中斷的等待機(jī)制
  • 支持多個(gè)等待條件

缺點(diǎn)

  • 實(shí)現(xiàn)復(fù)雜度高
  • 需要手動(dòng)管理鎖的獲取和釋放
  • 容易遺漏unlock導(dǎo)致死鎖

適用場(chǎng)景

  • 需要精確控制線程執(zhí)行順序的復(fù)雜場(chǎng)景
  • 多條件等待的線程協(xié)作
  • 對(duì)公平性有要求的場(chǎng)景

方法5:Semaphore - 基于許可的同步控制

實(shí)現(xiàn)原理

Semaphore通過(guò)維護(hù)一組許可(permits)來(lái)控制線程訪問(wèn)。初始化時(shí)指定許可數(shù)量,線程通過(guò)acquire()獲取許可,通過(guò)release()釋放許可。

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    // 初始化信號(hào)量:t1可以直接運(yùn)行,t2和t3需要等待
    private static Semaphore s1 = new Semaphore(1);
    private static Semaphore s2 = new Semaphore(0);
    private static Semaphore s3 = new Semaphore(0);

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                s1.acquire(); // 獲取許可
                System.out.println("線程1:數(shù)據(jù)加載");
                Thread.sleep(1000);
                s2.release(); // 釋放t2的許可
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                s2.acquire();
                System.out.println("線程2:數(shù)據(jù)處理");
                Thread.sleep(1000);
                s3.release();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread t3 = new Thread(() -> {
            try {
                s3.acquire();
                System.out.println("線程3:結(jié)果保存");
                Thread.sleep(1000);
                s1.release(); // 循環(huán)執(zhí)行時(shí)可重新開(kāi)始
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 啟動(dòng)線程
        t1.start();
        t2.start();
        t3.start();

        // 允許程序運(yùn)行一段時(shí)間后退出
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

進(jìn)階用法

  1. 公平模式new Semaphore(1, true)
  2. 批量獲取acquire(int permits)
  3. 非阻塞獲取tryAcquire()
  4. 超時(shí)控制tryAcquire(long timeout, TimeUnit unit)

優(yōu)點(diǎn)

  • 靈活控制并發(fā)度
  • 支持許可的申請(qǐng)和釋放
  • 可實(shí)現(xiàn)資源池等復(fù)雜模式

缺點(diǎn)

  • 需要仔細(xì)設(shè)計(jì)許可數(shù)量

方法6:CompletableFuture - 函數(shù)式異步編程

實(shí)現(xiàn)原理

CompletableFuture是Java 8引入的增強(qiáng)版Future,支持函數(shù)式編程風(fēng)格的任務(wù)編排。通過(guò)thenRun、thenApply等方法鏈?zhǔn)浇M合多個(gè)異步任務(wù)。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
    public static void main(String[] args) {
        // 創(chuàng)建異步任務(wù)鏈
        CompletableFuture<Void> taskChain = CompletableFuture
            .runAsync(() -> {
                System.out.println("任務(wù)1:初始化系統(tǒng)");
                sleep(1000);
            })
            .thenRunAsync(() -> {
                System.out.println("任務(wù)2:加載配置");
                sleep(1500);
            })
            .thenRunAsync(() -> {
                System.out.println("任務(wù)3:?jiǎn)?dòng)服務(wù)");
                sleep(500);
            })
            .thenRunAsync(() -> {
                System.out.println("任務(wù)4:運(yùn)行監(jiān)控");
            });
        
        // 等待所有任務(wù)完成
        try {
            taskChain.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
    
    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

優(yōu)點(diǎn)

  • 聲明式編程風(fēng)格
  • 強(qiáng)大的任務(wù)組合能力
  • 內(nèi)置異常處理機(jī)制
  • 與現(xiàn)代Java特性完美集成

缺點(diǎn)

  • 學(xué)習(xí)曲線較陡峭
  • 調(diào)試相對(duì)困難
  • Java 8+才支持

適用場(chǎng)景

  • 現(xiàn)代Java應(yīng)用開(kāi)發(fā)
  • 復(fù)雜的異步任務(wù)編排
  • 需要組合多個(gè)異步結(jié)果的場(chǎng)景
  • 響應(yīng)式編程基礎(chǔ)

三、常見(jiàn)問(wèn)題與解決方案

Q1:為什么await()要在while循環(huán)中調(diào)用?

A:這是為了防止"虛假喚醒"(spurious wakeup),即線程可能在沒(méi)有收到通知的情況下被喚醒。while循環(huán)會(huì)重新檢查條件,確保條件真正滿足。

Q2:如何避免死鎖?

A:遵循以下原則:

  • 按固定順序獲取多個(gè)鎖
  • 設(shè)置鎖超時(shí)時(shí)間
  • 避免在鎖中調(diào)用外部方法
  • 使用tryLock()替代lock()

以上就是Java中控制多線程順序執(zhí)行的六種實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于Java控制多線程順序執(zhí)行的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java8之lambda表達(dá)式基本語(yǔ)法

    Java8之lambda表達(dá)式基本語(yǔ)法

    本文通過(guò)示例大家給大家介紹了java8之lambda表達(dá)式的基本語(yǔ)法,感興趣的的朋友一起看看吧
    2017-08-08
  • Java 超詳細(xì)講解抽象類與接口的使用

    Java 超詳細(xì)講解抽象類與接口的使用

    對(duì)于面向?qū)ο缶幊虂?lái)說(shuō),抽象是它的一大特征之一,在 Java 中可以通過(guò)兩種形式來(lái)體現(xiàn)OOP的抽象:接口和抽象類,下面這篇文章主要給大家介紹了關(guān)于Java入門基礎(chǔ)之抽象類與接口的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Java 實(shí)現(xiàn)Redis存儲(chǔ)復(fù)雜json格式數(shù)據(jù)并返回給前端

    Java 實(shí)現(xiàn)Redis存儲(chǔ)復(fù)雜json格式數(shù)據(jù)并返回給前端

    這篇文章主要介紹了Java 實(shí)現(xiàn)Redis存儲(chǔ)復(fù)雜json格式數(shù)據(jù)并返回給前端操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • java獲取web容器地址的方法

    java獲取web容器地址的方法

    java獲取web容器地址的方法,需要的朋友可以參考一下
    2013-04-04
  • Spark SQL 編程初級(jí)實(shí)踐詳解

    Spark SQL 編程初級(jí)實(shí)踐詳解

    這篇文章主要為大家介紹了Spark SQL 編程初級(jí)實(shí)踐詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • SpringBoot + minio實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳功能

    SpringBoot + minio實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳功能

    MinIO是一個(gè)基于Go實(shí)現(xiàn)的高性能、兼容S3協(xié)議的對(duì)象存儲(chǔ),使用MinIO構(gòu)建用于機(jī)器學(xué)習(xí),分析和應(yīng)用程序數(shù)據(jù)工作負(fù)載的高性能基礎(chǔ)架構(gòu),這篇文章主要介紹了SpringBoot + minio實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳,需要的朋友可以參考下
    2023-06-06
  • 詳解idea maven nexus 常見(jiàn)命令配置

    詳解idea maven nexus 常見(jiàn)命令配置

    這篇文章主要介紹了idea maven nexus 常見(jiàn)命令配置的相關(guān)知識(shí),通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Java中EnumMap的使用解析

    Java中EnumMap的使用解析

    這篇文章主要介紹了Java中EnumMap的使用解析,EnumMap?是一種特殊的?Map,它要求自身所有的鍵來(lái)自某個(gè)枚舉類型,EnumMap?的內(nèi)部可以作為一個(gè)數(shù)組來(lái)實(shí)現(xiàn),因此它們的性能非常好,你可以放心地用?EnumMap?來(lái)實(shí)現(xiàn)基于枚舉的查詢,需要的朋友可以參考下
    2023-11-11
  • SpringBoot結(jié)合Maven項(xiàng)目依賴版本沖突問(wèn)題解決

    SpringBoot結(jié)合Maven項(xiàng)目依賴版本沖突問(wèn)題解決

    本文主要介紹了SpringBoot結(jié)合Maven項(xiàng)目依賴版本沖突問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 如何使用Spring+redis實(shí)現(xiàn)對(duì)session的分布式管理

    如何使用Spring+redis實(shí)現(xiàn)對(duì)session的分布式管理

    本篇文章主要介紹了如何使用Spring+redis實(shí)現(xiàn)對(duì)session的分布式管理,本文主要是在Spring中實(shí)現(xiàn)分布式session,采用redis對(duì)session進(jìn)行持久化管理,感興趣的小伙伴們可以參考一下
    2018-06-06

最新評(píng)論