5.park和unpark
目录
park和unpark
它们是 LockSupport
类中的方法
// 暂停当前线程
LockSupport.park();
// 恢复某个线程的运行
LockSupport.unpark(暂停线程对象)
简单使用
@Slf4j(topic = "c.TestPark")
public class TestPark {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("t1 start......");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.debug("do park");
LockSupport.park();
log.debug("resume......");
}, "t1");
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.debug("unpark......");
LockSupport.unpark(t1);
}
}
输出:
10:28:29.950 c.TestPark [t1] - t1 start......
10:28:30.952 c.TestPark [main] - unpark......
10:28:31.957 c.TestPark [t1] - do park
10:28:31.957 c.TestPark [t1] - resume......
Process finished with exit code 0
特点
与 Object
的 wait
& notify
相比
wait
,notify
和notifyAll
必须配合Object Monitor
一起使用,而park
,unpark
不必park
&unpark
是以线程为单位来【阻塞】和【唤醒】线程,而notify
只能随机唤醒一个等待线程,notifyAll
是唤醒所有等待线程,就不那么【精确】park
&unpark
可以先unpark
,而wait
¬ify
不能先notify
park 和 unpark 原理
==每个线程都有自己的一个parker对象(底层c语言实现的)==,由三部分组成 _counter
, _cond
和_mutex
线程像是一个旅行者,Parker像是他的旅行背包,条件变量像是背包中的帐篷。_counter 就好比背包中的备用干粮(0 为耗尽,1 为充足)
- 调用park就是判断是否需要停下来休息
- 如果备用干粮(_counter)耗尽,那么就钻进帐篷(条件变量)里休息
- 如果备用干粮(_counter)充足,那么不需要停留,继续前进。
- 调用
unpark
,就好比干粮(_counter)充足- 如果这时线程还在帐篷,就唤醒让他继续前进
- 如果这时线程还在运行,那么下次他调用
park
时,仅是消耗掉备用干粮,不需停留,继续前进 ,因为背包空间有限,多次调用unpark
仅会补充一份备用干粮(_counter),也就是多次unpark
后只会让紧跟着的一次park
失效
先调用park 再调用unpark
- 当前线程调用
Unsafe_park()
方法 - 检查
_counter,
本情况为0
,这时,获得_mutex
互斥锁 - 线程进入
_cond
条件变量阻塞 - 设置
_counter = 0
- 调用
Unsafe.unpark(Thread_0)
方法,设置_counter
为1
- 唤醒
_cond
条件变量中的Thread_0
Thread_0
恢复运行- 设置
_counter
为0
先调用unpark 再调用park
- 调用 Unsafe.unpark(Thread_0) 方法,设置 _counter 为 1
- 当前线程调用 Unsafe.park() 方法
- 检查 _counter ,本情况为 1,这时线程无需阻塞,继续运行
- 设置 _counter 为 0
@Slf4j(topic = "c.TestPark")
public class TestPark {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("t1 start......");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.debug("do park");
LockSupport.park();
log.debug("resume......");
}, "t1");
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.debug("unpark......");
LockSupport.unpark(t1);
}
}
输出:
11:47:58.747 c.TestPark [t1] - t1 start......
11:47:59.750 c.TestPark [main] - unpark......
11:48:00.754 c.TestPark [t1] - do park
11:48:00.754 c.TestPark [t1] - resume......
Process finished with exit code 0