Java中控制多線(xiàn)程執(zhí)行順序的8種方法
一、線(xiàn)程順序控制基礎(chǔ)概念
1.1 為什么需要控制線(xiàn)程順序
- 任務(wù)依賴(lài):B任務(wù)需要A任務(wù)的結(jié)果
- 資源初始化:配置線(xiàn)程需先于工作線(xiàn)程
- 數(shù)據(jù)一致性:確保操作按正確順序執(zhí)行
- 業(yè)務(wù)流程:滿(mǎn)足特定業(yè)務(wù)邏輯順序要求
1.2 常見(jiàn)應(yīng)用場(chǎng)景
- 日志系統(tǒng)的初始化與使用
- 數(shù)據(jù)庫(kù)連接池先啟動(dòng)后提供服務(wù)
- 多階段計(jì)算任務(wù)
- 事件驅(qū)動(dòng)架構(gòu)中的有序事件處理
二、基礎(chǔ)控制方法
2.1 Thread.join()方法
原理:當(dāng)前線(xiàn)程等待目標(biāo)線(xiàn)程終止
Thread t1 = new Thread(() -> System.out.println("Thread 1"));
Thread t2 = new Thread(() -> {
try {
t1.join(); // 等待t1完成
System.out.println("Thread 2");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
特點(diǎn):
- 簡(jiǎn)單直接
- 會(huì)阻塞調(diào)用線(xiàn)程
- 不支持復(fù)雜的依賴(lài)關(guān)系
2.2 單線(xiàn)程Executor
原理:使用單線(xiàn)程池自然保證順序
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> System.out.println("Task 2"));
executor.shutdown();
特點(diǎn):
- 自動(dòng)維護(hù)任務(wù)隊(duì)列
- 支持異步執(zhí)行
- 無(wú)法實(shí)現(xiàn)并行加速
三、同步工具類(lèi)控制
3.1 CountDownLatch
原理:允許線(xiàn)程等待直到計(jì)數(shù)器歸零
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
System.out.println("Thread 1");
latch.countDown();
}).start();
new Thread(() -> {
try {
latch.await(); // 等待latch釋放
System.out.println("Thread 2");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
特點(diǎn):
- 一次性使用
- 支持多線(xiàn)程等待
- 計(jì)數(shù)器不可重置
3.2 CyclicBarrier
原理:線(xiàn)程到達(dá)屏障點(diǎn)后等待其他線(xiàn)程
CyclicBarrier barrier = new CyclicBarrier(2,
() -> System.out.println("Barrier Action"));
new Thread(() -> {
try {
System.out.println("Thread 1 before barrier");
barrier.await();
System.out.println("Thread 1 after barrier");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("Thread 2 before barrier");
barrier.await();
System.out.println("Thread 2 after barrier");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
特點(diǎn):
- 可重復(fù)使用
- 支持屏障動(dòng)作
- 適用于多階段任務(wù)
3.3 Phaser
原理:靈活的多階段同步控制
Phaser phaser = new Phaser(1); // 注冊(cè)主線(xiàn)程
// 階段0
new Thread(() -> {
phaser.register();
System.out.println("Thread 1 phase 0");
phaser.arriveAndAwaitAdvance(); // 等待進(jìn)入階段1
System.out.println("Thread 1 phase 1");
phaser.arriveAndDeregister();
}).start();
// 階段0
new Thread(() -> {
phaser.register();
System.out.println("Thread 2 phase 0");
phaser.arriveAndAwaitAdvance(); // 等待進(jìn)入階段1
System.out.println("Thread 2 phase 1");
phaser.arriveAndDeregister();
}).start();
// 主線(xiàn)程控制階段推進(jìn)
Thread.sleep(1000);
phaser.arriveAndDeregister(); // 階段0完成
特點(diǎn):
- 動(dòng)態(tài)注冊(cè)/注銷(xiāo)
- 支持分層結(jié)構(gòu)
- 復(fù)雜但功能強(qiáng)大
四、鎖與條件變量
4.1 ReentrantLock + Condition
原理:通過(guò)條件變量精確控制線(xiàn)程喚醒
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
AtomicInteger flag = new AtomicInteger(0);
Thread t1 = new Thread(() -> {
lock.lock();
try {
while (flag.get() != 0) {
condition.await();
}
System.out.println("Thread 1");
flag.set(1);
condition.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
});
Thread t2 = new Thread(() -> {
lock.lock();
try {
while (flag.get() != 1) {
condition.await();
}
System.out.println("Thread 2");
flag.set(2);
condition.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
});
t1.start();
t2.start();
特點(diǎn):
- 靈活控制
- 支持公平/非公平鎖
- 需要手動(dòng)處理鎖的獲取釋放
五、高級(jí)并發(fā)工具
5.1 CompletableFuture
原理:函數(shù)式編程風(fēng)格的異步編排
CompletableFuture.runAsync(() -> System.out.println("Stage 1"))
.thenRun(() -> System.out.println("Stage 2"))
.thenRunAsync(() -> System.out.println("Stage 3"))
.join();
鏈?zhǔn)娇刂?/strong>:
CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(s -> s + " World")
.thenAccept(System.out::println)
.join();
特點(diǎn):
- 非阻塞式API
- 支持異常處理
- 可組合多個(gè)Future
5.2 ForkJoinPool + RecursiveTask
原理:分治算法中的有序控制
class OrderedTask extends RecursiveTask<Integer> {
private final int number;
OrderedTask(int number) {
this.number = number;
}
@Override
protected Integer compute() {
System.out.println("Processing: " + number);
if (number > 1) {
OrderedTask nextTask = new OrderedTask(number - 1);
nextTask.fork();
nextTask.join(); // 確保順序執(zhí)行
}
return number * 2;
}
}
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new OrderedTask(3));
特點(diǎn):
- 適合可分治問(wèn)題
- 工作竊取算法
- 自動(dòng)任務(wù)分解
六、線(xiàn)程通信控制
6.1 BlockingQueue
原理:通過(guò)隊(duì)列傳遞控制信號(hào)
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
Thread producer = new Thread(() -> {
try {
queue.put("Step 1 done");
System.out.println("Producer completed step 1");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread consumer = new Thread(() -> {
try {
String signal = queue.take();
System.out.println("Consumer received: " + signal);
System.out.println("Consumer executing step 2");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
特點(diǎn):
- 解耦生產(chǎn)消費(fèi)
- 支持有界/無(wú)界隊(duì)列
- 內(nèi)置阻塞機(jī)制
七、綜合對(duì)比與選型指南
| 方法 | 適用場(chǎng)景 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| Thread.join | 簡(jiǎn)單線(xiàn)性依賴(lài) | 簡(jiǎn)單直接 | 缺乏靈活性 |
| 單線(xiàn)程Executor | 任務(wù)隊(duì)列順序執(zhí)行 | 自動(dòng)管理線(xiàn)程 | 無(wú)法并行 |
| CountDownLatch | 一次性的多線(xiàn)程等待 | 支持多等待者 | 不可重置 |
| CyclicBarrier | 多階段協(xié)同 | 可重復(fù)使用 | 設(shè)計(jì)復(fù)雜 |
| Phaser | 動(dòng)態(tài)多階段控制 | 最靈活 | 學(xué)習(xí)曲線(xiàn)陡 |
| Lock+Condition | 精確條件控制 | 細(xì)粒度控制 | 需手動(dòng)管理 |
| CompletableFuture | 異步任務(wù)鏈 | 非阻塞API | 函數(shù)式風(fēng)格 |
| ForkJoinPool | 分治問(wèn)題 | 自動(dòng)并行 | 特定場(chǎng)景 |
| BlockingQueue | 生產(chǎn)消費(fèi)者模式 | 解耦組件 | 需要設(shè)計(jì)協(xié)議 |
八、最佳實(shí)踐與注意事項(xiàng)
- 避免死鎖:確保鎖的獲取釋放成對(duì)出現(xiàn)
- 處理中斷:正確響應(yīng)InterruptedException
- 資源清理:及時(shí)關(guān)閉線(xiàn)程池和釋放資源
- 性能考量:根據(jù)場(chǎng)景選擇合適控制方式
- 異常處理:確保異常不會(huì)破壞執(zhí)行順序
- 可讀性:復(fù)雜控制應(yīng)添加充分注釋
- 測(cè)試驗(yàn)證:多線(xiàn)程場(chǎng)景需充分測(cè)試
九、典型應(yīng)用案例
9.1 多階段數(shù)據(jù)處理
// 階段1:數(shù)據(jù)加載
CompletableFuture<List<Data>> loadFuture = CompletableFuture.supplyAsync(
() -> loadDataFromDB());
// 階段2:數(shù)據(jù)處理(依賴(lài)階段1)
CompletableFuture<List<Result>> processFuture = loadFuture.thenApplyAsync(
dataList -> processData(dataList));
// 階段3:結(jié)果保存(依賴(lài)階段2)
processFuture.thenAcceptAsync(
resultList -> saveResults(resultList))
.exceptionally(ex -> {
System.err.println("Error: " + ex.getMessage());
return null;
});
9.2 并發(fā)初始化控制
CountDownLatch initLatch = new CountDownLatch(3);
List<Thread> initThreads = Arrays.asList(
new Thread(() -> { initConfig(); initLatch.countDown(); }),
new Thread(() -> { initCache(); initLatch.countDown(); }),
new Thread(() -> { initDB(); initLatch.countDown(); })
);
initThreads.forEach(Thread::start);
// 主線(xiàn)程等待初始化完成
initLatch.await();
startService();
總結(jié)
Java提供了豐富的線(xiàn)程順序控制機(jī)制,從簡(jiǎn)單的Thread.join()到復(fù)雜的Phaser,開(kāi)發(fā)者可以根據(jù)具體場(chǎng)景選擇最合適的方案。理解各種方法的適用場(chǎng)景和實(shí)現(xiàn)原理,是編寫(xiě)正確、高效并發(fā)程序的關(guān)鍵。在實(shí)際開(kāi)發(fā)中,應(yīng)當(dāng):
- 優(yōu)先考慮高層抽象(如CompletableFuture)
- 在需要精細(xì)控制時(shí)使用底層同步工具
- 始終注意線(xiàn)程安全和資源管理
- 通過(guò)充分測(cè)試驗(yàn)證執(zhí)行順序的正確性
掌握這些線(xiàn)程控制技術(shù),可以有效地解決并發(fā)編程中的順序控制難題,構(gòu)建出健壯可靠的多線(xiàn)程應(yīng)用。
以上就是Java中控制多線(xiàn)程執(zhí)行順序的8種方法的詳細(xì)內(nèi)容,更多關(guān)于Java控制多線(xiàn)程執(zhí)行順序的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Nacos與SpringBoot實(shí)現(xiàn)配置管理的開(kāi)發(fā)實(shí)踐
在微服務(wù)架構(gòu)中,配置管理是一個(gè)核心組件,而Nacos為此提供了一個(gè)強(qiáng)大的解決方案,本文主要介紹了Nacos與SpringBoot實(shí)現(xiàn)配置管理的開(kāi)發(fā)實(shí)踐,具有一定的參考價(jià)值2023-08-08
解析Spring Data JPA的Audit功能之審計(jì)數(shù)據(jù)庫(kù)變更
Spring Data JPA 提供了Audit審計(jì)功能,用來(lái)記錄創(chuàng)建時(shí)間、創(chuàng)建人、修改時(shí)間、修改人等,下面來(lái)詳細(xì)講解下審計(jì)數(shù)據(jù)庫(kù)變更2021-06-06
Spring Boot應(yīng)用程序同時(shí)支持HTTP和HTTPS協(xié)議的實(shí)現(xiàn)方法
如今,企業(yè)級(jí)應(yīng)用程序的常見(jiàn)場(chǎng)景是同時(shí)支持HTTP和HTTPS兩種協(xié)議,這篇文章考慮如何讓Spring Boot應(yīng)用程序同時(shí)支持HTTP和HTTPS兩種協(xié)議,需要的朋友可以參考下2019-10-10
Java輕松使用工具類(lèi)實(shí)現(xiàn)獲取wav時(shí)間長(zhǎng)度
在Java中,工具類(lèi)定義了一組公共方法,這篇文章將介紹Java中使用工具類(lèi)來(lái)獲取一個(gè)wav文件的時(shí)間長(zhǎng)度,感興趣的同學(xué)繼續(xù)往下閱讀吧2021-10-10
SpringMVC對(duì)自定義controller入?yún)㈩A(yù)處理方式
這篇文章主要介紹了SpringMVC對(duì)自定義controller入?yún)㈩A(yù)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
淺談springboot一個(gè)service內(nèi)組件的加載順序
這篇文章主要介紹了springboot一個(gè)service內(nèi)組件的加載順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家2021-08-08
深入Parquet文件格式設(shè)計(jì)原理及實(shí)現(xiàn)細(xì)節(jié)
這篇文章主要介紹了深入Parquet文件格式設(shè)計(jì)原理及實(shí)現(xiàn)細(xì)節(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08

