Park和UnPark底层原理

1. 简介

park和unpark也是一个线程暂停技术(让线程进入wait状态),与wait/notify不同的是,前者是LockSupport类中的方法,后者是Object类中的方法。其次,wait与notify和notifyall必须配合Object Monitor一起使用,而park和unpark不必一起使用。park和unpark是以线程为单位来阻塞和唤醒线程的,而notify只能随机唤醒一个等待线程。最后park和unpark可以先unpark,而wait和notify不行。

2. 底层原理

每个线程都有自己的一个Parker对象(c代码实现),由三个部分组成_counter,_cond, _mutex,打个比喻:

  1. 线程就像一个旅人,Parker就是其携带的背包,条件变量(_cond)就好比背包中的帐篷,_couter就好比备用的干粮
  2. 调用park就是看需不需要停下来休息,如果干粮没有了就进帐篷休息,如果还有干粮就继续前进
  3. 调用unpark就好比令干粮充足,如果现在线程还在帐篷中,就唤醒他继续前进,如果线程还在运行,那么下次它调用park,仅消耗掉备用干粮,继续前进,因为背包容量有限,所以多次调用unpark只会补充一份干粮。

先调用park,再调用unpark:
在这里插入图片描述

  1. 当前线程调用unsafe.park()方法
  2. 检查_counter,本情况为0,这是,获得_mutex互斥锁
  3. 线程进入cond条件变量阻塞
  4. 设置_counter=0

在这里插入图片描述

  1. 调用Unsafe.unpark(Thread 0)方法,设置counter为1
  2. 唤醒_cond条件变量中的Thread_0
  3. Thread 0恢复运行
  4. 设置_countre为0

先调用unpark再调用park:
在这里插入图片描述

  1. 调用Unsafe.unpark(Thread_0)方法,设置_counter为1
  2. 当前线程调用Unsafe.park()方法
  3. 检查_counter,本情况为1,这时现场无需阻塞,继续运行
  4. 设置_counter为0

3. 总结

先调用 park 再调用 unpark:如果先调用 park,那么当前线程将进入阻塞状态,等待被其他线程调用 unpark 方法唤醒。
先调用 unpark 再调用 park:如果先调用 unpark,它将为当前线程创建一个"许可证",以便稍后可以使用。这个许可证不会累积,每个线程最多只能有一个许可证。当稍后调用 park 时,如果已经有一个 “许可证”(通过先调用 unpark 而获得),那么 park 不会阻塞,它会消耗掉许可证,线程继续执行。如果没有可用的许可证,park 将阻塞。

所以,先调用 unpark 再调用 park 通常用于确保某个操作发生之前,线程不会被阻塞,而先调用 park 再调用 unpark 则用于将线程置于阻塞状态,等待特定条件的发生。需要注意的是,unpark 方法可以多次调用,但它只会为一个线程创建一个许可证。如果多次调用 unpark,线程仍然只会有一个许可证,而不会累积多个许可证。这意味着多次调用 unpark 不会使 park 方法重复消耗多个许可证。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值