JUC 底层支持 LockSupport
线程等待和唤醒三种方式
方式 | 等待 | 唤醒 | 描述 |
---|---|---|---|
Object | wait | notity/notifyAll | 必须用在 synchronized 里,需要先等待再唤醒 |
Condition | await | singal | 必须用在 Lock 块中,需要先等待再唤醒 |
LockSupport | park | unpark | 无限制 |
wait/notify
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
// 线程 A 要先等待,且必须用在 synchronized 中
new Thread(() -> {
synchronized (obj) {
System.out.println("线程A come in...");
try {
obj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程A 被唤醒");
}
}, "线程A").start();
TimeUnit.SECONDS.sleep(1);
// 唤醒的线程必须已经处理等待中,先唤醒后等待就不行,也必须用在 synchronized 中
new Thread(() -> {
synchronized (obj) {
obj.notify();
System.out.println("线程B 发出通知");
}
}, "线程B").start();
}
await/singal
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 线程 A 要先等待,且必须用在 lock 代码块中
new Thread(() -> {
lock.lock();
System.out.println("线程A come in...");
try {
condition.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}, "线程A").start();
TimeUnit.SECONDS.sleep(1);
// 唤醒的线程必须已经处理等待中,先唤醒后等待就不行,也必须用在 lock 代码块中
new Thread(() -> {
lock.lock();
try {
condition.signal();
System.out.println("线程B 发出通知");
} finally {
lock.unlock();
}
}, "线程B").start();
}
park/unpark
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
TimeUnit.SECONDS.sleep(2); // 线程 A 休眠,让线程 B 先执行(模拟先唤醒后等待)
System.out.println("线程A come in...");
LockSupport.park();
System.out.println("线程A 被唤醒");
}, "线程A");
t1.start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
System.out.println("线程B 发出通知");
LockSupport.unpark(t1);
}, "线程B").start();
}
LockSupport 常用方法
方法 | 解释 | 备注 |
---|---|---|
park() | 阻塞线程 | 当前线程没有令牌就一直阻塞 |
parkNanos(long nanos) | 阻塞线程多少纳秒 | 时间结束或有令牌将唤醒(相对时间) |
parkUntil(long deadline) | 阻塞线程到具体时间 | 到了时间或有令牌将唤醒(绝对时间) |
unpark(Thread t) | 给指定线程颁发令牌 | 最多持有一个令牌 |
各种阻塞方法区别
-
Thread.sleep() 和 Object.wait()
- sleep 不能外部唤醒,只能自己醒过来,wait 既可以外部唤醒,也可以自己醒过来
- 最大的区别就是 sleep 不会释放锁,wait 会释放锁
-
Object.wait() 和 Condition.await():
- Object.wait() 是个 native 方法, jvm 实现;Condition.await() JDK 实现,底层调用 LockSupport.park() 实现
- Condition.await() 先把线程加入 AQS 的条件队列,然后把 AQS 的 state -1,最后才是调用 LockSupport.park() 阻塞队列
-
Thread.sleep() 和 LockSupport.park()
LockSupport.park() 还有几个兄弟方法:parkNanos()、parkUtil()
- sleep 不能外部唤醒,只能自己醒过来,LockSupport.park() 可以自己醒过来也可以外部唤醒
- sleep 是 native 方法,LockSupport.park() 底层调了 Unsafe 的 native 方法
- 两者都不会释放锁
-
Object.wait() 和 LockSupport.park()
- Object.wait() 方法需要用在 synchronized 块中,LockSupport.park() 无限制
- Object.wait() 不带超时的,需要另一个线程执行 notify() 来唤醒,但不一定继续执行后续内容
- LockSupport.park() 不带超时的,需要另一个线程执行 unpark() 来唤醒,一定会继续执行后续内容
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具