本文目录导读:

- 使用 Thread.sleep() - 最简单的等待
- 使用 wait() 和 notify() - 对象级别的等待
- 使用 CountDownLatch - 多个线程等待一个事件
- 使用 CyclicBarrier - 多个线程相互等待
- 使用 CompletableFuture - 异步编程中的等待
- 使用 LockSupport - 灵活的线程阻塞
- 使用 Phaser - 分阶段同步
- 最佳实践建议
在Java中实现线程等待主要有以下几种方式,我将通过具体案例来说明:
使用 Thread.sleep() - 最简单的等待
public class SleepExample {
public static void main(String[] args) {
System.out.println("开始执行");
try {
// 线程暂停3秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3秒后继续执行");
}
}
使用 wait() 和 notify() - 对象级别的等待
public class WaitNotifyExample {
private static final Object lock = new Object();
private static boolean condition = false;
public static void main(String[] args) {
// 等待线程
Thread waiter = new Thread(() -> {
synchronized (lock) {
System.out.println("等待线程: 开始等待条件...");
try {
while (!condition) {
lock.wait(); // 释放锁并等待
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("等待线程: 条件满足,继续执行");
}
});
// 通知线程
Thread notifier = new Thread(() -> {
synchronized (lock) {
System.out.println("通知线程: 准备设置条件并通知");
try {
Thread.sleep(2000); // 模拟一些工作
} catch (InterruptedException e) {
e.printStackTrace();
}
condition = true;
lock.notify(); // 唤醒等待线程
System.out.println("通知线程: 已发送通知");
}
});
waiter.start();
notifier.start();
}
}
使用 CountDownLatch - 多个线程等待一个事件
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
// 创建3个工作线程
for (int i = 1; i <= 3; i++) {
final int workerId = i;
new Thread(() -> {
System.out.println("工作线程 " + workerId + " 开始工作");
try {
Thread.sleep((long) (Math.random() * 3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("工作线程 " + workerId + " 完成工作");
latch.countDown(); // 计数器减1
}).start();
}
System.out.println("主线程等待所有工作线程完成");
latch.await(); // 主线程等待,直到计数器变为0
System.out.println("所有工作线程完成,主线程继续执行");
}
}
使用 CyclicBarrier - 多个线程相互等待
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
int threadCount = 3;
CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
System.out.println("所有线程都到达屏障点,执行汇总操作");
});
for (int i = 1; i <= threadCount; i++) {
final int threadId = i;
new Thread(() -> {
try {
System.out.println("线程 " + threadId + " 执行阶段1");
Thread.sleep((long) (Math.random() * 2000));
System.out.println("线程 " + threadId + " 到达屏障点,等待其他线程");
barrier.await(); // 等待所有线程到达
System.out.println("线程 " + threadId + " 继续执行阶段2");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
使用 CompletableFuture - 异步编程中的等待
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("开始异步任务");
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "异步任务结果";
});
// 等待异步任务完成
String result = future.get();
System.out.println("获取到结果: " + result);
// 或者使用回调方式,不阻塞主线程
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "另一个异步任务";
});
future2.thenAccept(System.out::println);
System.out.println("主线程继续执行,不会被阻塞");
// 等待所有任务完成
Thread.sleep(3000);
}
}
使用 LockSupport - 灵活的线程阻塞
import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
public static void main(String[] args) {
Thread waitingThread = new Thread(() -> {
System.out.println("等待线程: 准备阻塞");
LockSupport.park(); // 阻塞当前线程
System.out.println("等待线程: 被唤醒,继续执行");
// 可以配合中断使用
if (Thread.currentThread().isInterrupted()) {
System.out.println("等待线程: 被中断");
}
});
Thread unparkThread = new Thread(() -> {
System.out.println("唤醒线程: 准备唤醒");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LockSupport.unpark(waitingThread); // 唤醒指定线程
System.out.println("唤醒线程: 已发送唤醒信号");
});
waitingThread.start();
unparkThread.start();
}
}
使用 Phaser - 分阶段同步
import java.util.concurrent.Phaser;
public class PhaserExample {
public static void main(String[] args) {
Phaser phaser = new Phaser(3) { // 3个参与者
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("阶段 " + phase + " 完成,当前注册者: " + registeredParties);
return registeredParties == 0; // 返回true表示终止
}
};
for (int i = 1; i <= 3; i++) {
final int threadId = i;
new Thread(() -> {
System.out.println("线程 " + threadId + " 开始阶段1");
phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段1
System.out.println("线程 " + threadId + " 开始阶段2");
phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段2
System.out.println("线程 " + threadId + " 结束");
}).start();
}
}
}
最佳实践建议
-
选择合适的方式:
- 简单延时使用
Thread.sleep() - 线程间协作使用
wait()/notify() - 多线程等待一个事件使用
CountDownLatch - 多线程相互等待使用
CyclicBarrier或Phaser - 异步编程使用
CompletableFuture - 灵活控制使用
LockSupport
- 简单延时使用
-
注意事项:
- 始终处理
InterruptedException - 在
wait()中使用 while 循环检查条件 - 避免在持有锁时调用
Thread.sleep() - 优先使用 java.util.concurrent 包中的工具类
- 始终处理
这些案例覆盖了Java中主要的线程等待实现方式,你可以根据具体需求选择最合适的方法。