• LockSupport类


    一、LockSupport的介绍

    LockSupport,构建同步组件的基础工具,帮AQS完成相应线程的阻塞或者唤醒的工作。LockSupport所有的方法都是静态方法,可以让线程在任意位置阻塞。这个类与每个使用它的线程相关联一个许可证(最多一个),如果许可证可用,则在此过程中消耗它; 否则线程会被等待。

    二、LockSupport的常用方法

    LockSupport类的主要方法如下:

    public static void park(Object blocker); // 暂停当前线程
    public static void parkNanos(Object blocker, long nanos); // 暂停当前线程,不过有超时时间的限制,
    public static void parkUntil(Object blocker, long deadline); // 暂停当前线程,直到某个时间
    public static void park(); // 无期限暂停当前线程
    public static void parkNanos(long nanos); // 暂停当前线程,不过有超时时间的限制,时间是纳秒!,不是毫秒!,更不是秒!
    public static void parkUntil(long deadline); // 暂停当前线程,直到某个时间
    public static void unpark(Thread thread); // 恢复线程 thread
    public static Object getBlocker(Thread t);
    

    Object blocker其实就是方便在线程dump的时候看到具体的阻塞对象的信息。

    三、LockSupport的原理

    每个线程都有自己的一个 Parker 对象,由三部分组成 _counter , _cond 和 _mutex 打个比喻

    • 线程就像一个旅人,Parker 就像他随身携带的背包,条件变量就好比背包中的帐篷。_counter 就好比背包中的备用干粮(0 为耗尽,1 为充足,最多只能为1)
    • 调用 park 就是要看需不需要停下来歇息
      • 如果备用干粮耗尽(_counter =0),那么钻进帐篷歇息(线程暂停)
      • 如果备用干粮充足,那么不需停留,继续前进
    • 调用 unpark,就好比令干粮充足
      • 如果这时线程还在帐篷(处于暂停状态),就唤醒让他继续前进(恢复线程)
      • 如果这时线程还在运行,那么下次他调用 park 时,仅是消耗掉备用干粮,不需停留继续前进

    值得注意的是:_counter最多只能为1;

    图解:

    park线程

    image-20201009145432328

    1. 当前线程调用 Unsafe.park() 方法

    2. 检查 _counter ,本情况为 0,这时,获得 _mutex 互斥锁

    3. 线程进入 _cond 条件变量阻塞

    4. 设置 _counter = 0

    unpark唤醒park的线程:

    image-20201009150405240

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

    2. 唤醒 _cond 条件变量中的 Thread_0

    3. Thread_0 恢复运行

    4. 设置 _counter 为 0

    先unpark再park:

    image-20201009150659559

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

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

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

    4. 设置 _counter 为 0

    四、代码测试

    测试一下先unpark在park的情况:

    public class LockSupportTest{
    public static void main(String[] args) throws InterruptedException {
         
            test4();
        }
    
        private static void test4() throws InterruptedException {
            final Object obj = new Object();
            Thread t1 = new Thread(() -> {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    			  System.out.println("park...");
                //禁用当前线程进行线程调度,除非时间过了,或者interrupt或者unpark();
                synchronized (obj) {
                    LockSupport.park(1000l);
    
                    }
                    System.out.println("unpark");
            });
            t1.start();
            LockSupport.unpark(t1);
            System.out.println("先unpark");
        }
    }
    

    结果:线程先unpark,_counter 会保存一个信号量(最多只能一个),等到下一次park的时候线程就可以直接运行不必暂停.

    五、总结:

    image-20201009152102148

    图片来自博客https://blog.csdn.net/u013332124/article/details/84647915

  • 相关阅读:
    anchor-free : CornerNet 和 CenterNet 简要笔记
    图像分割中的loss--处理数据极度不均衡的状况
    python 装饰器
    python3 新特性
    VSCode Eslint+Prettier+Vetur常用配置
    JS lodash学习笔记
    JS 高端操作整理
    Vue 组件通信
    Vue 搭建vue-element-admin框架
    小程序 HTTP请求封装
  • 原文地址:https://www.cnblogs.com/myblogstart/p/13786101.html
Copyright © 2020-2023  润新知