LockSupport.park() 不需 synchronized,wait() 必须在同步块中;前者依赖许可机制、可提前 unpark,后者依赖对象监视器、notify 必须在 wait 后生效。

LockSupport.park() 不需要 synchronized,但 wait() 必须在同步块里
这是最直接的差异:调用 wait() 前必须已持有对象锁,否则抛 IllegalMonitorStateException;而 LockSupport.park() 完全不检查线程是否持有任何锁,它只看当前线程有没有许可(permit)。
常见错误现象:wait() 被写在 if 或 while 外面、没加 synchronized、或者锁的是别的对象,结果一执行就崩;LockSupport.park() 则不会因“没锁”报错,但可能一直挂起——因为没许可又没人 unpark()。
- 使用场景:
wait()/notify()适合线程间协作,比如生产者-消费者共用一个队列对象做锁;LockSupport更底层,适合实现自定义同步器(如AbstractQueuedSynchronizer) - 参数差异:
wait()可传超时时间或不传;park()有park()、parkNanos(long)、parkUntil(long)三种,语义更明确 - 性能影响:
wait()涉及 monitor 的竞争与唤醒队列管理,开销略高;park()是 JVM 直接操作线程状态,更轻量
unpark() 可以在 park() 之前调用,wait() 不行
LockSupport.unpark(Thread) 发放许可是“可累积”的:如果目标线程还没 park(),许可就存着,等它下次 park() 时直接消费,不会阻塞。而 notify() 必须在 wait() 阻塞期间或之后调用才有效,提前调用等于白叫——被忽略,且无法重发。
常见错误现象:用 wait()/notify() 实现简单信号,却把 notify() 写在 wait() 前面,结果接收方永远等下去;换成 unpark()/park() 就能绕过这个时序陷阱。
立即学习“Java免费学习笔记(深入)”;
- 使用场景:线程启动后先做初始化,再等待信号;或异步回调触发唤醒,但目标线程可能还没开始
park() - 注意点:
unpark()发一次只给一个许可,连续两次unpark()和一次park()效果一样——许可不会叠加成两个 - 兼容性影响:JDK 1.5+ 全平台支持
LockSupport,无额外依赖
park() 被中断时会立即返回,wait() 会先清除中断状态再抛 InterruptedException
park() 在响应中断时只是“醒来”,并保留中断状态(Thread.interrupted() 仍为 true),不抛异常;而 wait() 醒来后会清中断状态,并主动抛出 InterruptedException,强制你处理。
常见错误现象:用 park() 等待时没检查中断状态,导致线程看似“醒了”,实则被中断却继续执行后续逻辑;而 wait() 的异常如果被空 catch,就彻底丢失中断信号。
- 实操建议:用
park()后应立刻检查Thread.currentThread().isInterrupted(),决定是否退出循环 - 示例:
while (!done) { LockSupport.park(); if (Thread.currentThread().isInterrupted()) { break; } // do work } - 性能提示:避免在循环里反复调用
isInterrupted(),它本身开销极小,但语义上必须查
LockSupport 没有“对象监视器”概念,不能替代 wait/notify 的条件等待语义
wait() 天然绑定在某个对象监视器上,配合 notify() 可实现“多个线程等不同条件”;LockSupport 只认线程,不认条件,也没有“唤醒所有等待者”或“按条件唤醒”的能力。
容易踩的坑:试图用 LockSupport 模拟 notifyAll() ——只能遍历线程列表挨个 unpark(),但无法保证它们等的是同一逻辑条件,极易引发竞态或重复处理。
- 使用场景限制:适合一对一唤醒(如线程池 worker 等待任务)、或作为同步器内部原语;不适合替代传统管程模型
- 关键区别:
wait()释放锁 + 进入等待队列;park()不释放任何锁,也不关联任何资源,纯线程调度 - 复杂点在于:真正用好
LockSupport往往要搭配Unsafe、CAS 和队列结构,不是单靠它就能写出正确并发逻辑的










