一、引言:线程协作的基石

在Java并发编程中,Object.wait()是实现线程间精确协调的核心方法。作为java.lang.Object类的基础方法,它与notify()/notifyAll()共同构成监视器模式的三大支柱。本文将深入剖析:

  • 方法签名:public final void wait() throws InterruptedException
  • 底层定位:JVM本地方法(native实现)
  • 历史沿革:从JDK 1.0至今的演进

经典生产者-消费者模型示例

class Buffer {
    private Queue<Integer> queue = new LinkedList<>();
    private int 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.poll();
        notifyAll(); // 唤醒生产者
        return item;
    }
}

二、方法机制深度解析
1. 三重原子操作

调用wait()时发生的关键步骤:

  1. 释放锁:立即释放对象监视器锁
  2. 线程阻塞:进入WAITING状态
  3. 等待唤醒:移入该对象的等待集合(Wait Set)

$$ \text{Thread State Transition: } \text{RUNNABLE} \xrightarrow{\text{wait()}} \text{WAITING} $$

2. 唤醒条件矩阵
唤醒方式 锁获取策略 适用场景
notify() 随机选择单个线程 单任务处理场景
notifyAll() 唤醒所有竞争线程 多条件等待场景
超时唤醒 指定时间后自动唤醒 故障恢复机制
3. 虚假唤醒(Spurious Wakeup)防御

必须使用循环条件检查

synchronized(lock) {
    while (!condition) {  // 不能用if
        lock.wait();
    }
    // 执行业务逻辑
}

原因:操作系统级信号可能导致意外唤醒(概率<0.1%)

三、底层实现原理
1. JVM监视器结构
graph LR
    A[Object Header] --> B[Mark Word]
    A --> C[Monitor Object]
    C --> D[Entry Set]
    C --> E[Wait Set]
    C --> F[Owner]

  • Entry Set:竞争锁的线程集合
  • Wait Set:执行wait()的线程集合
  • Owner:当前持有锁的线程
2. 本地方法调用链
Object.wait() 
→ JVM_MonitorWait() 
→ ObjectSynchronizer::wait() 
→ ObjectMonitor::wait()

3. 关键C++源码片段(OpenJDK)
void ObjectMonitor::wait(jlong millis, bool interruptible) {
    Thread * const Self = THREAD;
    // 1. 检查中断状态
    if (interruptible && Thread::is_interrupted(Self, true)) {
        throw InterruptedException();
    }
    // 2. 创建WaitNode加入等待队列
    WaitNode node(Self, millis);
    AddWaiter(&node);
    // 3. 释放锁
    exit(Self);
    // 4. 进入等待状态
    while (!node._notified) {
        Self->_ParkEvent->park(millis);
    }
    // 5. 重新获取锁
    enter(Self);
}

四、进阶使用模式
1. 多条件等待
class BoundedBuffer {
    private final Object notFull = new Object();
    private final Object notEmpty = new Object();
    
    public void put(Object item) {
        synchronized (notFull) {
            while (isFull()) notFull.wait();
            // 入队操作
            synchronized (notEmpty) {
                notEmpty.notify();
            }
        }
    }
}

2. 超时控制策略
synchronized(lock) {
    long remaining = TimeUnit.SECONDS.toNanos(5);
    while (!condition && remaining > 0) {
        remaining = lock.wait(remaining); 
    }
}

3. 中断处理最佳实践
try {
    synchronized(lock) {
        while (!condition) {
            lock.wait();
        }
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // 恢复中断状态
    // 执行清理操作
}

五、性能优化与陷阱规避
1. 性能对比测试
操作 纳秒级耗时 (Intel i9)
wait() 1200±200ns
parkNanos() 800±150ns
yield() 35±10ns
2. 常见陷阱解决方案
  • 死锁场景
    synchronized(A) {
        synchronized(B) {
            B.wait(); // 错误!持有A锁时等待B
        }
    }
    

  • 通知丢失:使用notifyAll()替代notify()
  • 优先级反转:配合Thread.setPriority()
3. Lock/Condition替代方案
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
    while (!conditionMet) {
        condition.await();
    }
} finally {
    lock.unlock();
}

六、实战案例剖析
1. 数据库连接池实现
public class ConnectionPool {
    private List<Connection> pool = new ArrayList<>();
    private int maxSize;
    
    public Connection getConnection() throws InterruptedException {
        synchronized (this) {
            while (pool.isEmpty()) {
                wait();
            }
            return pool.remove(0);
        }
    }
    
    public void releaseConnection(Connection conn) {
        synchronized (this) {
            pool.add(conn);
            notifyAll();
        }
    }
}

2. 分布式任务调度协调
class TaskCoordinator {
    private int completedTasks = 0;
    
    public void taskCompleted() {
        synchronized(this) {
            completedTasks++;
            if (completedTasks == totalTasks) {
                notifyAll(); // 唤醒所有等待线程
            }
        }
    }
    
    public void waitForCompletion() throws InterruptedException {
        synchronized(this) {
            while (completedTasks < totalTasks) {
                wait();
            }
        }
    }
}

七、总结与展望

Object.wait()作为Java并发原语,其核心价值在于:

  1. 实现精确的线程状态控制
  2. 提供低级别的线程通信机制
  3. 构建高效资源协调模型

未来演进方向

  • 与虚拟线程(Project Loom)的集成
  • 响应式编程中的异步适配
  • 机器学习场景下的动态等待策略

"掌握wait()/notify()机制,就握住了Java并发编程的命脉" —— Brian Goetz(Java并发之父)


附录:扩展阅读

  1. Java内存模型(JMM)与happens-before原则
  2. java.util.concurrent工具包实现对比
  3. 操作系统级线程调度原理解析

本文完整代码示例可访问:[GitHub仓库链接]
(注:实际博客需补充完整代码示例和性能测试数据)

Logo

纵情码海钱塘涌,杭州开发者创新动! 属于杭州的开发者社区!致力于为杭州地区的开发者提供学习、合作和成长的机会;同时也为企业交流招聘提供舞台!

更多推荐