1. 方法概述
LokSupport 包含以下方法
void park();
void park(Object blocker);
void parkNanos(long nanos);
void parkNanos(Object blocker, long nanos);
void parkUntil(long deadline);
void parkUntil(Object blocker, long deadline);
void unpark(Thread thread);
- blocker 我们一般传递 this ,没啥实际作用。这个阻塞对象会出现在线程 dump 中,方便我们分析问题。
- parkNanos 可以指定最大堵塞时间, 纳秒
- partUntil 参数是一个绝对值,等待到什么时候
2. 使用例子
import java.util.concurrent.locks.LockSupport;
class Solution {
public static void main(String[] args) {
Thread comsumer = new Thread(() -> {
while (true) {
System.out.println("等待包子");
LockSupport.park();
System.out.println("吃上包子");
System.out.println("------------");
}
});
comsumer.start();
new Thread(() -> {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("包子做好了");
LockSupport.unpark(comsumer);
}
}).start();
}
}
3. 和 Thread.sleep 的区别
- 从功能上来说,Thread.sleep() 和 LockSupport.park() 方法类似,都是阻塞当前线程的执行,且都不会释放当前线程占有的锁资源;
- Thread.sleep() 没法从外部唤醒,只能自己醒过来,LockSupport.park() 方法可以被另一个线程调用 LockSupport.unpark() 方法唤醒;
- Thread.sleep() 方法声明上抛出了 InterruptedException 中断异常,所以调用者需要捕获这个异常或者再抛出,LockSupport.park()方法不需要捕获中断异常;
- Thread.sleep() 本身就是一个 native 方法;
- LockSupport.park() 底层是调用的 Unsafe 的 native 方法;
4. 和 wait() 的区别
- Object.wait() 方法需要在 synchronized 块中执行;LockSupport.park()可以在任意地方执行;
- Object.wait() 方法声明抛出了中断异常,调用者需要捕获或者再抛出;
- LockSupport.park() 不需要捕获中断异常
- Object.wait() 不带超时的,需要另一个线程执行 notify() 来唤醒,但不一定继续执行后续内容;
- LockSupport.park() 不带超时的,需要另一个线程执行 unpark() 来唤醒,一定会继续执行后续内容;
- 如果在wait()之前执行了 notify(),会抛出 IllegalMonitorStateException 异常;
- 如果在 park() 之前执行了 unpark() ,线程不会被阻塞,直接跳过park(),继续执行后续内容;
功能点 | 精准控制 | 执行顺序 | 中断 |
---|---|---|---|
wait/notify | 挂起:指定当前线程挂起 唤醒:随机唤醒 1 个线程或全部唤醒 | 执行顺序需要严格保证 wait 操作发生在 notify 之前,如果 notify 在 wait 之前执行了,那么 wait 操作将进入无限等待的窘境 | 响应中断,且需处理编译期异常 |
park/unpark | 挂起:指定当前线程挂起 唤醒:精确唤醒指定的 1 个线程 注:虽然唤醒可指定某线程,但挂起操作只会针对当前线程生效,因为当前线程并不了解被挂起线程的真实状态,如果一旦可操控,势必会带来不可预期的安全问题 | unpark 操作可发生在 park 之前,但仅会生效一次;例如针对线程A首先执行了2次 unpark 操作,然后对A第1次执行 park 操作时不会有阻塞,但第2次执行 park 时会进入等待 | 响应中断,但不抛出异常,发生中断后,park() 方法会自动结束,通过 Thread.interrupted() 来判断是中断还是 unpark() 导致的 |