在 Java 中,若需要控制线程间的依赖关系(如 C 线程依赖 B 线程的结果),可以通过以下几种方式实现:
方案 1:使用 CountDownLatch
CountDownLatch 是一个同步工具类,允许一个或多个线程等待其他线程完成操作。
实现步骤:
- 定义一个 CountDownLatch,初始计数设为 1(表示 B 线程完成后需要触发一次通知)。
- B 线程执行完成后,调用 countDown() 方法减少计数。
- C 线程启动时调用 await(),阻塞直到计数变为 0(即 B 线程完成)。
示例代码:
import java.util.concurrent.CountDownLatch;
public class ThreadDependentExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
// 启动线程 B,完成后触发 latch.countDown()
Thread bThread = new Thread(() -> {
System.out.println("B 线程开始执行");
// 模拟 B 的处理逻辑
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("B 线程完成");
latch.countDown(); // 通知 C 可以执行
});
// 启动线程 C,等待 B 完成后执行
Thread cThread = new Thread(() -> {
try {
System.out.println("C 线程等待 B 完成");
latch.await(); // 阻塞直到 B 完成
System.out.println("C 线程开始执行,B 已完成");
// C 的处理逻辑
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("C 线程被中断");
}
});
// 启动线程 A(独立执行)
Thread aThread = new Thread(() -> {
System.out.println("A 线程开始执行");
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println("A 线程完成");
});
// 启动所有线程
aThread.start();
bThread.start();
cThread.start();
}
}
方案 2:使用 CompletableFuture
CompletableFuture 是 Java 8 引入的高级异步编程工具,支持链式依赖关系。
实现步骤:
- 将 B 的任务包装为 CompletableFuture。
- 通过 thenRun 或 thenApply 方法,将 C 的任务绑定到 B 的完成后执行。
- 线程 A 可独立运行(通过 runAsync 并行执行)。
示例代码:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
// 线程 B 的任务
CompletableFuture<Void> bFuture = CompletableFuture.runAsync(() -> {
System.out.println("B 线程开始执行");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("B 线程完成");
});
// 线程 C 的任务绑定在 B 完成后执行
bFuture.thenRun(() -> {
System.out.println("C 线程开始执行,B 已完成");
// C 的处理逻辑
});
// 线程 A 的任务独立运行
CompletableFuture<Void> aFuture = CompletableFuture.runAsync(() -> {
System.out.println("A 线程开始执行");
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println("A 线程完成");
});
// 等待所有任务完成(可选)
try {
CompletableFuture.allOf(aFuture, bFuture).get();
} catch (Exception e) {
e.printStackTrace();
}
}
}
方案 3:使用 Thread.join()
Thread.join() 方法可以让当前线程等待另一个线程执行完毕。
实现步骤:
- 启动线程 B 和 A。
- 在 C 线程的 run 方法中调用 bThread.join(),确保 B 完成后再执行 C。
示例代码:
public class ThreadJoinExample {
public static void main(String[] args) {
// 启动线程 B
Thread bThread = new Thread(() -> {
System.out.println("B 线程开始执行");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("B 线程完成");
});
// 启动线程 C,需等待 B 完成
Thread cThread = new Thread(() -> {
try {
System.out.println("C 线程等待 B 完成");
bThread.join(); // 等待 B 线程完成
System.out.println("C 线程开始执行,B 已完成");
// C 的处理逻辑
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("C 线程被中断");
}
});
// 启动线程 A(独立执行)
Thread aThread = new Thread(() -> {
System.out.println("A 线程开始执行");
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println("A 线程完成");
});
// 启动所有线程
aThread.start();
bThread.start();
cThread.start();
}
}
关键注意事项
- 线程安全:若 C 需要使用 B 的结果(如共享数据),需确保数据操作线程安全(如通过 volatile、锁或原子类)。
- 异常处理:确保线程执行过程中捕获异常,避免程序崩溃。
- 资源释放:及时关闭线程池或释放资源,避免内存泄漏。
- 性能调优:若任务频繁执行,优先选择 CompletableFuture 或线程池优化性能。
方案对比
| 方法 | 适用场景 | 优点 | 缺点 |
| CountDownLatch | 需要等待多个线程完成后再执行后续任务 | 简单易用,支持多个依赖项 | 需手动管理计数,线程间耦合较紧 |
| CompletableFuture | 复杂异步任务链,需要链式依赖、结果传递 | 高内聚、可组合,支持异常处理和超时 | 学习成本较高,API 较复杂 |
| Thread.join() | 仅需要等待一个线程完成,代码简洁 | 代码简洁,直接调用 | 只能等待单个线程,无法扩展到多个依赖项 |
根据需求选择最合适的方法:
• 若需要链式异步任务,优先使用 CompletableFuture。
• 若需要简单依赖关系,可选 CountDownLatch 或 Thread.join()。