Java等待的基本概念
在Java多线程编程中,"等待"是一个核心概念,它指的是线程暂停执行,直到满足特定条件后再继续运行。Java提供了多种等待机制,每种机制都有其特定的使用场景和优势。
为什么需要等待机制
多线程环境中,线程间的协调至关重要。当多个线程共享资源或需要按特定顺序执行时,等待机制可以:
- 避免资源竞争
- 提高程序效率
- 确保线程安全
- 实现线程间的通信
Java中的主要等待方式
Java平台提供了三种主要的等待实现方式:
1. Object.wait()
方法
2. Thread.sleep()
方法
3. Lock
和Condition
接口
Object.wait()方法详解
Object.wait()
是Java中最基础的等待机制,它允许线程释放对象锁并进入等待状态,直到其他线程调用该对象的notify()
或notifyAll()
方法。
wait()方法的基本用法
```java
synchronized (sharedObject) {
while (!condition) {
sharedObject.wait();
}
// 执行条件满足后的操作
}
### wait()方法的三个重要特性
1. **释放锁**:调用wait()会立即释放对象锁
2. **等待通知**:线程会保持等待直到收到通知
3. **虚假唤醒**:可能在没有通知的情况下被唤醒,因此条件检查应在循环中进行
### wait()与notify()的配合使用
```java
// 等待线程
synchronized (lock) {
while (!ready) {
lock.wait();
}
System.out.println("继续执行");
}
// 通知线程
synchronized (lock) {
ready = true;
lock.notifyAll();
}
Thread.sleep()方法分析
虽然Thread.sleep()
也能实现等待效果,但它与Object.wait()
有本质区别。
sleep()的特点
- 不会释放任何锁
- 不需要在同步块中调用
- 只是让当前线程暂停执行指定时间
- 不能被中断(会抛出InterruptedException)
sleep()的典型使用场景
// 简单延时
try {
Thread.sleep(1000); // 暂停1秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
高级等待机制:Lock和Condition
Java 5引入的java.util.concurrent.locks
包提供了更灵活的等待机制。
Lock接口的优势
- 更细粒度的锁控制
- 可以尝试获取锁
- 支持公平锁
- 支持多个Condition
Condition的使用示例
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 等待线程
lock.lock();
try {
while (!conditionMet) {
condition.await();
}
// 执行操作
} finally {
lock.unlock();
}
// 通知线程
lock.lock();
try {
conditionMet = true;
condition.signal();
} finally {
lock.unlock();
}
Java等待的最佳实践
避免常见的等待陷阱
- 忘记在循环中检查条件:可能导致虚假唤醒问题
- 错误处理InterruptedException:应恢复中断状态
- 持有锁时间过长:影响程序性能
- 过度使用sleep():可能导致响应性问题
性能优化建议
- 优先使用
notifyAll()
除非确定只有一个等待线程 - 考虑使用
java.util.concurrent
包中的高级工具类 - 对于超时等待,使用带有超时参数的wait()方法
- 在适当场景下考虑使用自旋锁
Java 8及以后版本中的等待改进
CompletableFuture提供的异步等待
CompletableFuture.supplyAsync(() -> {
// 异步任务
}).thenAccept(result -> {
// 结果处理
}).join(); // 等待完成
新的并发工具类
StampedLock
:改进的读写锁Phaser
:更灵活的同步屏障ForkJoinPool
:工作窃取线程池
实际应用案例:生产者消费者问题
使用wait/notify实现
class Buffer {
private Queue<Integer> queue = new LinkedList<>();
private int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
}
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == capacity) {
wait();
}
queue.add(item);
notifyAll();
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
int item = queue.remove();
notifyAll();
return item;
}
}
使用Lock和Condition实现
class Buffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
// 其余代码类似,使用await/signal代替wait/notify
}
总结与选择指南
Java提供了丰富的等待机制,选择哪种方式取决于具体需求:
- 简单同步:使用
synchronized
配合wait/notify
- 定时等待:使用带有超时参数的
wait()
或sleep()
- 高级控制:使用
Lock
和Condition
- 异步编程:考虑
CompletableFuture
- 高性能场景:探索
java.util.concurrent
中的高级工具
理解这些等待机制的区别和适用场景,是编写高效、可靠多线程Java程序的关键。