在Java中常常使用到多线程处理一些业务,但是也会遇到多线程处理时带来的业务逻辑时序不对问题,例如需要等待一个业务处理完或者下一步的逻辑需要等待多线程得到的结果,下面是几种常用的方法
- 使用 Thread.join() 方法
对于已知的线程列表,可以遍历列表并调用每个线程的 join() 方法。join() 会让当前线程阻塞,直到指定的线程执行完毕。
List<Thread> threads = ...; // 创建并启动线程的列表for (Thread t : threads) {t.join(); // 当前线程(主线程)会等待t线程执行完毕
}// 这里所有的线程都已经执行完毕
System.out.println("All threads have finished.");
- 使用 CountDownLatch
CountDownLatch 是一个计数器,允许一个或多个线程等待其他一组线程完成操作。初始化时设定一个计数值,每当一个任务完成时,调用 countDown() 方法使计数值减一。当计数值变为零时,所有等待在 await() 方法上的线程将被释放。
import java.util.concurrent.CountDownLatch;CountDownLatch latch = new CountDownLatch(NUM_THREADS); // 初始化计数器,NUM_THREADS为线程数量for (int i = 0; i < NUM_THREADS; i++) {Thread worker = new Thread(() -> {// 执行任务...latch.countDown(); // 任务完成,计数器减一});worker.start();
}latch.await(); // 主线程在此处等待,直到计数器归零(即所有任务完成)System.out.println("All threads have finished.");
- 使用 CyclicBarrier
CyclicBarrier 是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点(即所有线程都到达)才继续执行。与 CountDownLatch 不同的是,它可以重用,并且在所有线程到达屏障时可以触发一个回调操作。
import java.util.concurrent.CyclicBarrier;CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {System.out.println("All threads have reached the barrier.");
});for (int i = 0; i < NUM_THREADS; i++) {Thread worker = new Thread(() -> {// 执行任务...try {barrier.await(); // 当前线程到达屏障点并阻塞,直到所有线程都到达} catch (InterruptedException | BrokenBarrierException e) {// 处理异常}});worker.start();
}
- 使用 ExecutorService 和 Future
如果使用 java.util.concurrent.ExecutorService 来管理线程池,可以利用其提供的 shutdown() 和 awaitTermination() 方法来等待所有任务完成:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);// 提交任务到线程池
for (Runnable task : tasks) {executor.submit(task);
}executor.shutdown(); // 停止接收新任务,现有任务继续执行try {if (!executor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) { // 等待所有任务完成,超时抛出异常executor.shutdownNow(); // 尝试强制停止未完成的任务throw new TimeoutException("Tasks did not finish within the specified timeout.");}
} catch (InterruptedException e) {executor.shutdownNow(); // 当前线程被中断,尝试强制停止未完成的任务Thread.currentThread().interrupt(); // 重新设置中断状态
}System.out.println("All tasks have finished.");