object类不提供队列能力,其wait/notify是实现基于锁的阻塞队列的关键原语,需在synchronized中使用监视器协作;真正队列逻辑须自行用数组或链表实现,wait/notify仅作信号开关。

Java 中 Object 类本身不提供线程等待与唤醒的“队列”能力,但它提供的 wait()、notify() 和 notifyAll() 是实现**基于锁的阻塞队列底层逻辑**的关键原语。这些方法必须在 synchronized 块中调用,依赖对象监视器(monitor)实现线程协作。
核心原理:wait/notify 与条件等待
wait() 让当前线程释放锁并进入该对象的等待队列(wait set),直到被 notify() 或 notifyAll() 唤醒;唤醒后需重新竞争锁,获得锁后才从 wait() 返回。这天然适合实现“生产者-消费者”场景下的阻塞行为:
- 队列满时,生产者调用
queue.wait()暂停,等待消费者取走元素后通知 - 队列空时,消费者调用
queue.wait()暂停,等待生产者放入元素后通知 - 必须用 while 循环检查条件,而非 if——防止虚假唤醒(spurious wakeup)
关键实现细节:synchronized + 条件循环 + notifyAll()
以简易数组型阻塞队列为例,底层需围绕一个共享对象(如 this 或专用锁对象)同步所有操作:
- 所有访问队列状态(size、head、tail)、修改数据的操作,都必须包裹在
synchronized(this)块中 -
put()中:若满 →while (isFull()) wait();插入后notifyAll()(唤醒可能等待的消费者) -
take()中:若空 →while (isEmpty()) wait();取出后notifyAll()(唤醒可能等待的生产者) - 使用
notifyAll()而非notify()更安全——避免唤醒错误类型的线程(比如只唤醒另一个生产者,而消费者仍在沉睡)
为什么不用 Object 自己管理队列?
Object.wait() 的等待队列是 JVM 内部维护的、与对象监视器绑定的链表,并非用户可读写的队列结构。它只负责挂起/唤醒线程,**不存储业务数据**。真正的队列逻辑(如元素存储、入队出队指针、容量控制)必须由你用数组或链表等数据结构独立实现,wait/notify 仅作为线程协作的“信号开关”。
对比现代方案:Lock + Condition 更清晰
虽然 Object 方式可行,但 JDK 5+ 推荐使用 java.util.concurrent.locks.Lock 和 Condition:
-
Condition明确分离“非空”和“非满”两个等待条件(notEmpty.await()/notFull.await()) - 支持公平性、中断响应、超时等待等高级特性
- 避免
notifyAll()唤醒所有线程的性能开销 -
ArrayBlockingQueue等 JDK 阻塞队列正是基于ReentrantLock+ 双Condition实现
不复杂但容易忽略:真正安全的阻塞队列,靠的是“原子状态检查 + 可重入锁 + 条件循环 + 精准唤醒”,Object 提供了最基础的协作原语,但组织逻辑全在你的代码里。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











