在多线程编程中,有时需要确保多个线程按特定顺序执行,或者等待所有线程执行完毕后再获取结果。以下是几种常见的实现方式及其原理和示例代码。
1. 使用 CountDownLatch
CountDownLatch
可以用于等待一组线程完成操作。通过设置初始计数值,每个线程完成任务后调用 countDown()
方法,主线程调用 await()
方法等待计数器归零。
原理
- 计数器:初始化一个计数器,表示需要等待的线程数量。
- 等待:主线程调用
await()
方法等待计数器归零。 - 计数器减一:每个线程完成任务后调用
countDown()
方法,计数器减一。 - 释放等待线程:当计数器归零时,主线程被释放,继续执行。
示例代码
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int numberOfThreads = 3;
CountDownLatch latch = new CountDownLatch(numberOfThreads);
for (int i = 0; i < numberOfThreads; i++) {
final int taskNumber = i;
new Thread(() -> {
System.out.println("Task " + taskNumber + " is starting.");
try {
Thread.sleep((taskNumber + 1) * 1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " is done.");
latch.countDown();
}).start();
}
System.out.println("Main thread is waiting for all tasks to finish...");
latch.await();
System.out.println("All tasks are done. Main thread continues.");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
2. 使用 CyclicBarrier
CyclicBarrier
用于一组线程互相等待,直到所有线程都到达屏障点。所有线程到达屏障点后,可以继续执行。
原理
- 屏障点:所有线程调用
await()
方法等待,直到所有线程都到达屏障点。 - 可重用:
CyclicBarrier
可以重用,所有线程通过屏障点后屏障可以被重置。
示例代码
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
int numberOfThreads = 3;
CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
System.out.println("All threads have reached the barrier. Barrier action is executed.");
});
for (int i = 0; i < numberOfThreads; i++) {
final int taskNumber = i;
new Thread(() -> {
System.out.println("Task " + taskNumber + " is starting.");
try {
Thread.sleep((taskNumber + 1) * 1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " is waiting at the barrier.");
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " is done.");
}).start();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
3. 使用 ExecutorService
和 invokeAll
ExecutorService
提供了 invokeAll
方法,可以提交一组任务并等待所有任务完成。
原理
- 提交任务:使用
ExecutorService
提交一组Callable
任务。 - 等待完成:调用
invokeAll
方法等待所有任务完成,并获取结果。
示例代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class ExecutorServiceInvokeAllExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> tasks = new ArrayList<>();
for (int i = 0; i < 3; i++) {
final int taskNumber = i;
tasks.add(() -> {
System.out.println("Task " + taskNumber + " is starting.");
try {
Thread.sleep((taskNumber + 1) * 1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " is done.");
return "Result from Task " + taskNumber;
});
}
System.out.println("Main thread is submitting tasks...");
List<Future<String>> futures = executorService.invokeAll(tasks);
System.out.println("Main thread is waiting for all tasks to finish...");
for (Future<String> future : futures) {
System.out.println(future.get());
}
executorService.shutdown();
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
4. 使用 CompletableFuture
CompletableFuture
提供了强大的异步编程和组合式任务执行功能,可以用于等待多个任务完成。
原理
- 提交任务:使用
CompletableFuture
提交多个异步任务。 - 等待完成:使用
CompletableFuture.allOf
等方法等待所有任务完成。
示例代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("Task 1 is starting.");
try {
Thread.sleep(1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task 1 is done.");
return "Result from Task 1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("Task 2 is starting.");
try {
Thread.sleep(2000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task 2 is done.");
return "Result from Task 2";
});
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("Task 3 is starting.");
try {
Thread.sleep(1500); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task 3 is done.");
return "Result from Task 3";
});
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
System.out.println("Main thread is waiting for all tasks to finish...");
allFutures.get();
System.out.println("All tasks are done. Main thread continues.");
System.out.println("Result from Task 1: " + future1.get());
System.out.println("Result from Task 2: " + future2.get());
System.out.println("Result from Task 3: " + future3.get());
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
5. 使用 Phaser
Phaser
用于管理一组线程的阶段同步,可以用于确保多个线程按阶段执行。
原理
- 阶段:每个阶段可以有多个线程参与,所有线程到达阶段的屏障点后,可以继续执行下一阶段。
- 可重用:
Phaser
可以重用,支持多个阶段的同步。
示例代码
import java.util.concurrent.Phaser;
public class PhaserExample {
public static void main(String[] args) {
int numberOfThreads = 3;
Phaser phaser = new Phaser(numberOfThreads);
for (int i = 0; i < numberOfThreads; i++) {
final int taskNumber = i;
new Thread(() -> {
System.out.println("Task " + taskNumber + " is starting phase 1.");
try {
Thread.sleep((taskNumber + 1) * 1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " is done phase 1.");
phaser.arriveAndAwaitAdvance();
System.out.println("Task " + taskNumber + " is starting phase 2.");
try {
Thread.sleep((taskNumber + 1) * 1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " is done phase 2.");
phaser.arriveAndAwaitAdvance();
}).start();
}
phaser.awaitAdvance(phaser.getPhase());
System.out.println("All tasks are done phase 1. Main thread continues.");
phaser.awaitAdvance(phaser.getPhase());
System.out.println("All tasks are done phase 2. Main thread continues.");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
6. 使用 Thread.join
Thread.join
方法可以等待一个线程执行完毕。
原理
- 等待:主线程调用
join
方法等待指定线程执行完毕。 - 顺序执行:通过多个
join
调用确保线程按顺序执行。
示例代码
public class ThreadJoinExample {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
System.out.println("Task 1 is starting.");
try {
Thread.sleep(1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task 1 is done.");
});
Thread thread2 = new Thread(() -> {
System.out.println("Task 2 is starting.");
try {
Thread.sleep(2000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task 2 is done.");
});
Thread thread3 = new Thread(() -> {
System.out.println("Task 3 is starting.");
try {
Thread.sleep(1500); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task 3 is done.");
});
thread1.start();
thread2.start();
thread3.start();
thread1.join();
System.out.println("Task 1 is finished.");
thread2.join();
System.out.println("Task 2 is finished.");
thread3.join();
System.out.println("Task 3 is finished.");
System.out.println("All tasks are done. Main thread continues.");
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.