在多线程编程中,有时需要确保多个线程按特定顺序执行,或者等待所有线程执行完毕后再获取结果。以下是几种常见的实现方式及其原理和示例代码。

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. 使用 ExecutorServiceinvokeAll

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.