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

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. 資源的有序訪問(避免競(jìng)爭(zhēng)條件)

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

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

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

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

join()方法會(huì)使當(dāng)前線程等待目標(biāo)線程執(zhí)行完畢。通過在主線程中依次調(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)原理

通過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)

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

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

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

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

CountDownLatch通過計(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ù)庫連接建立");
            latch1.countDown(); // t1完成后打開閘門1
        });
        
        Thread t2 = new Thread(() -> {
            try {
                latch1.await(); // 等待閘門1打開
                System.out.println("查詢用戶數(shù)據(jù)");
                latch2.countDown(); // t2完成后打開閘門2
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        Thread t3 = new Thread(() -> {
            try {
                latch2.await(); // 等待閘門2打開
                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à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,避免無效喚醒
  3. volatile變量:確保狀態(tài)標(biāo)志的可見性
  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通過維護(hù)一組許可(permits)來控制線程訪問。初始化時(shí)指定許可數(shù)量,線程通過acquire()獲取許可,通過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í)可重新開始
            } 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ù)編排。通過thenRunthenApply等方法鏈?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)用開發(fā)
  • 復(fù)雜的異步任務(wù)編排
  • 需要組合多個(gè)異步結(jié)果的場(chǎng)景
  • 響應(yīng)式編程基礎(chǔ)

三、常見問題與解決方案

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

A:這是為了防止"虛假喚醒"(spurious wakeup),即線程可能在沒有收到通知的情況下被喚醒。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)文章

  • IDEA導(dǎo)入項(xiàng)目報(bào)錯(cuò)java程序包不存在問題及解決

    IDEA導(dǎo)入項(xiàng)目報(bào)錯(cuò)java程序包不存在問題及解決

    在IDEA導(dǎo)入項(xiàng)目時(shí),若出現(xiàn)javafx包不存在錯(cuò)誤,需檢查并更改為JDK1.8版本(原默認(rèn)為JDK14),同時(shí)確保模塊目錄正確、Tomcat配置無誤,并補(bǔ)全JavaFX依賴,即可解決運(yùn)行問題
    2025-09-09
  • 淺談Java字符串比較的三種方法

    淺談Java字符串比較的三種方法

    這篇文章主要介紹了淺談Java字符串比較的三種方法,字符串比較是常見的操作,包括比較相等、比較大小、比較前綴和后綴串等,需要的朋友可以參考下
    2023-04-04
  • SpringBoot后端實(shí)現(xiàn)小程序微信登錄功能實(shí)現(xiàn)

    SpringBoot后端實(shí)現(xiàn)小程序微信登錄功能實(shí)現(xiàn)

    微信小程序登錄是開發(fā)者通過微信提供的身份驗(yàn)證機(jī)制,獲取用戶唯一標(biāo)識(shí)(openid)和會(huì)話密鑰(session_key)的過程,這篇文章給大家介紹SpringBoot后端實(shí)現(xiàn)小程序微信登錄功能實(shí)現(xiàn),感興趣的朋友跟隨小編一起看看吧
    2025-05-05
  • SpringBoot WebSocket實(shí)時(shí)監(jiān)控異常的詳細(xì)流程

    SpringBoot WebSocket實(shí)時(shí)監(jiān)控異常的詳細(xì)流程

    最近做了一個(gè)需求,消防的設(shè)備巡檢,如果巡檢發(fā)現(xiàn)異常,通過手機(jī)端提交,后臺(tái)的實(shí)時(shí)監(jiān)控頁面實(shí)時(shí)獲取到該設(shè)備的信息及位置,然后安排員工去處理。這篇文章主要介紹了SpringBoot WebSocket實(shí)時(shí)監(jiān)控異常的全過程,感興趣的朋友一起看看吧
    2021-10-10
  • 使用Java 壓縮文件打包tar.gz 包的詳細(xì)教程

    使用Java 壓縮文件打包tar.gz 包的詳細(xì)教程

    本文帶領(lǐng)大家學(xué)習(xí)如何使用Java 壓縮文件打包tar.gz 包,主要通過 Apache compress 工具打包,通過示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • 從零搭建SpringBoot+MyBatisPlus快速開發(fā)腳手架

    從零搭建SpringBoot+MyBatisPlus快速開發(fā)腳手架

    這篇文章主要為大家介紹了從零搭建SpringBoot+MyBatisPlus快速開發(fā)腳手架示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 使用Spring的FactoryBean創(chuàng)建和獲取Bean對(duì)象方式

    使用Spring的FactoryBean創(chuàng)建和獲取Bean對(duì)象方式

    這篇文章主要介紹了使用Spring的FactoryBean創(chuàng)建和獲取Bean對(duì)象方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Nacos框架服務(wù)注冊(cè)實(shí)現(xiàn)流程

    Nacos框架服務(wù)注冊(cè)實(shí)現(xiàn)流程

    這篇文章主要介紹了SpringCloud服務(wù)注冊(cè)之nacos實(shí)現(xiàn)過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • Activiti7與Spring以及Spring Boot整合開發(fā)

    Activiti7與Spring以及Spring Boot整合開發(fā)

    這篇文章主要介紹了Activiti7與Spring以及Spring Boot整合開發(fā),在Activiti中核心類的是ProcessEngine流程引擎,與Spring整合就是讓Spring來管理ProcessEngine,有感興趣的同學(xué)可以參考閱讀
    2023-03-03
  • servlet基礎(chǔ)知識(shí)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    servlet基礎(chǔ)知識(shí)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了servlet基礎(chǔ)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07

最新評(píng)論

台东县| 安图县| 东海县| 庆城县| 扎兰屯市| 六枝特区| 延长县| 黄陵县| 建水县| 信丰县| 电白县| 虞城县| 闵行区| 高平市| 瓦房店市| 长治县| 咸阳市| 和田市| 西林县| 定安县| 通化市| 米泉市| 温宿县| 兴安县| 文安县| 称多县| 金门县| 镇原县| 青田县| 库尔勒市| 蒙自县| 巨野县| 南华县| 武清区| 九江市| 洪雅县| 应用必备| 莱州市| 金塔县| 亳州市| 涪陵区|