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) | 阻塞到一个具体时间,自1970年1月1日以来的毫秒数 | 到了指定的时间会自我唤醒(绝对时间) |
| 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()阻塞队列
- Object.wait() 是个 native 方法, jvm 实现;Condition.await() JDK 实现(底层调用
-
Thread.sleep() 和 LockSupport.park()
LockSupport.park() 还有几个兄弟方法:parkNanos()、parkUtil()
- sleep 不能外部唤醒,只能自己醒过来,LockSupport.park() 可以自己醒过来也可以外部唤醒
- sleep 是 native 方法,LockSupport.park() 底层调了 Unsafe 的 native 方法
- 两者都不会释放锁(单纯就方法来说是这样,其实 park 一般会配合 aqs 使用,aqs 中会通过其他途径释放锁)
-
Object.wait() 和 LockSupport.park()
- Object.wait() 方法需要用在 synchronized 块中,LockSupport.park() 无限制
- Object.wait() 不带超时的,需要另一个线程执行 notify() 来唤醒,但不一定继续执行后续内容
- LockSupport.park() 不带超时的,需要另一个线程执行 unpark() 来唤醒,一定会继续执行后续内容

浙公网安备 33010602011771号