并发编程学习(六):park、unpark

本文解析了LockSupport类中的park和unpark方法的工作原理,以及它们与wait和notify的区别,涉及线程阻塞、唤醒机制和底层实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、 park、unpark介绍

parkunpark它们是LockSupport类中的方法,内部调用的是Unsafe类中的native方法。

 // 暂停当前线程,暂停后,线程状态变为 WAITING

LockSupport.park();

// 恢复某个线程的运行,恢复后线程状态变为RUNNING

LockSupport.unpark(要恢复的线程对象);

        先park再unpark的方式是容易理解的。但还有一个场景,先unpark后再次执行park方法,也不会阻塞调用了park方法的线程。理解为park方法就是校验获取一个通行令牌,而unpark方法是获取到一个通行令牌的过程。先执行unpark方法,代表先获得了通行令牌。在另一个线程调用park方法时,校验到这个令牌存在,消耗掉这个令牌然后就可以继续往下走。

代码示例: 

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            log.debug("start...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("park...");
            LockSupport.park();
            log.debug("resume...");
        },"t1");

        t1.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("unpark...");
        LockSupport.unpark(t1);

    }
}

输出结果:

15:45:21.606 [t1] DEBUG com.example.common.thread.TestLockSupport - start...
15:45:22.617 [t1] DEBUG com.example.common.thread.TestLockSupport - park...
15:45:56.229 [main] DEBUG com.example.common.thread.TestLockSupport - unpark...
15:49:31.797 [t1] DEBUG com.example.common.thread.TestLockSupport - resume...

2、wait/notify与park/unpark区别 

  1. wait、notify 、notifyAll必须配合Object Monitor (即对象锁)一起使用,而park、unpark不必。
  2. park、unpark是以线程为单位来【阻塞】和【唤醒】线程; 而notify只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,就不那么【精确】。
  3. park、unpark可以先unpark;而wait、notify不能先notify。

3、 park、unpark原理

每个线程都有自己的一个Parker对象(该Parker对象是底层的c代码实现的),由三部分组成:

_counter(代表了一个标志位)、_cond(表了内部的一个阻塞队列) 和 _mutex 。

比如:

        线程就像一个旅人,Parker就像他随身携带的背包,条件变量就好比背包中的帐篷。_counter就好比背包中的干粮(0为耗尽,1为充足)。

        调用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、设置_counter为0.

1、 调用Unsafe.unpark(Thread_0)方法,设置_counter为1 。

2、当前线程调用Unsafe.park()方法。

3、检查_counter,本情况为1,这时线程无需阻塞,继续运行。

4、设置_counter为0。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值