本文目录导读:

我来详细讲解Java线程唤醒的几种典型操作案例。
使用wait/notify机制
基础生产者-消费者案例
public class WaitNotifyExample {
// 共享资源
private static final Object lock = new Object();
private static boolean taskCompleted = false;
public static void main(String[] args) throws InterruptedException {
// 等待线程
Thread waiter = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("等待线程开始执行,等待条件满足...");
while (!taskCompleted) {
lock.wait(); // 释放锁并等待
}
System.out.println("等待线程被唤醒,条件已满足");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 通知线程
Thread notifier = new Thread(() -> {
synchronized (lock) {
try {
Thread.sleep(2000); // 模拟工作
taskCompleted = true;
System.out.println("通知线程完成任务,准备唤醒等待线程");
lock.notify(); // 唤醒等待线程
System.out.println("通知线程已发送唤醒信号");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
waiter.start();
Thread.sleep(100); // 确保等待线程先获得锁
notifier.start();
}
}
生产者-消费者完整案例
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumerExample {
private static final int MAX_SIZE = 5;
private final Queue<Integer> buffer = new LinkedList<>();
public static void main(String[] args) {
ProducerConsumerExample example = new ProducerConsumerExample();
// 生产者线程
Thread producer = new Thread(() -> {
int value = 0;
while (true) {
try {
synchronized (example) {
// 缓冲区满则等待
while (example.buffer.size() == MAX_SIZE) {
System.out.println("缓冲区已满,生产者等待...");
example.wait();
}
// 生产数据
example.buffer.offer(value);
System.out.println("生产者生产了: " + value + ",缓冲区大小: " + example.buffer.size());
value++;
// 唤醒消费者
example.notifyAll();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 消费者线程
Thread consumer = new Thread(() -> {
while (true) {
try {
synchronized (example) {
// 缓冲区空则等待
while (example.buffer.isEmpty()) {
System.out.println("缓冲区为空,消费者等待...");
example.wait();
}
// 消费数据
int value = example.buffer.poll();
System.out.println("消费者消费了: " + value + ",缓冲区大小: " + example.buffer.size());
// 唤醒生产者
example.notifyAll();
}
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
consumer.start();
}
}
使用ReentrantLock + Condition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class LockConditionExample {
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean ready = false;
public static void main(String[] args) throws InterruptedException {
LockConditionExample example = new LockConditionExample();
// 等待线程
Thread waiter = new Thread(() -> {
lock.lock();
try {
System.out.println("等待线程开始执行");
while (!example.ready) {
System.out.println("等待条件满足...");
example.condition.await(); // 类似wait()
}
System.out.println("等待线程被唤醒,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
// 通知线程
Thread notifier = new Thread(() -> {
lock.lock();
try {
Thread.sleep(2000);
example.ready = true;
System.out.println("通知线程设置条件为true");
example.condition.signal(); // 类似notify()
System.out.println("通知线程已发送信号");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
waiter.start();
Thread.sleep(100);
notifier.start();
}
}
使用Semaphore(信号量)
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private final Semaphore semaphore = new Semaphore(0); // 初始许可为0
public static void main(String[] args) throws InterruptedException {
SemaphoreExample example = new SemaphoreExample();
// 等待线程
Thread waiter = new Thread(() -> {
try {
System.out.println("等待线程开始执行");
example.semaphore.acquire(); // 获取许可,如果没有则阻塞
System.out.println("等待线程获取到许可,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 释放线程
Thread releaser = new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("释放线程准备释放许可");
example.semaphore.release(); // 释放许可,唤醒等待线程
System.out.println("释放线程已释放许可");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
waiter.start();
Thread.sleep(100);
releaser.start();
}
}
使用CountDownLatch
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
// 等待线程
Thread waiter = new Thread(() -> {
try {
System.out.println("等待线程开始执行");
latch.await(); // 等待计数器归零
System.out.println("等待线程被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 触发线程
Thread trigger = new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("触发线程准备唤醒等待线程");
latch.countDown(); // 计数器减1,当为0时唤醒所有等待线程
System.out.println("触发线程已完成操作");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
waiter.start();
Thread.sleep(100);
trigger.start();
}
}
使用CompletableFuture
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) throws Exception {
// 创建一个被阻塞的CompletableFuture
CompletableFuture<String> future = new CompletableFuture<>();
// 等待线程
Thread waiter = new Thread(() -> {
try {
System.out.println("等待线程开始执行");
String result = future.get(); // 阻塞等待结果
System.out.println("等待线程收到结果: " + result);
} catch (Exception e) {
e.printStackTrace();
}
});
// 完成线程
Thread completer = new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("完成线程准备完成future");
future.complete("Hello from completer!");
System.out.println("完成线程已完成future");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
waiter.start();
Thread.sleep(100);
completer.start();
// 等待完成
completer.join();
waiter.join();
}
}
重要注意事项
-
始终在循环中等待:避免虚假唤醒
while (!condition) { wait(); } -
避免死锁:确保在正确的时机释放锁
-
优先使用高级并发工具:如CountDownLatch、CyclicBarrier等
-
注意性能:notifyAll比notify更安全,但可能影响性能
-
异常处理:InterruptedException需要妥善处理
这些案例涵盖了Java中主要的线程唤醒机制,根据具体场景选择合适的方案。