千家信息网

LockSupport的原理和作用是什么

发表于:2024-10-23 作者:千家信息网编辑
千家信息网最后更新 2024年10月23日,本篇内容介绍了"LockSupport的原理和作用是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成
千家信息网最后更新 2024年10月23日LockSupport的原理和作用是什么

本篇内容介绍了"LockSupport的原理和作用是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

LockSupport是什么

用于创建锁和其他同步类的基本线程阻塞原语。
使用它,可以用来构建一些特定逻辑的锁。jdk并发包的AQS框架就依赖了它。

LockSupport有什么作用

它提供了线程的阻塞和唤醒。
每当一个线程使用它,那么就可以当作这个线程维持了一个二元信号量,可以比作持有许可证。
调用pack()方法,如果有许可证,那么消耗它并且直接返回,线程继续执行下去。反之,则阻塞。
调用unpack()方法,如果许可证不可用,那么就变成可用,如果是可用,那么就不做其他操作。也就是说,许可证不可以多次累加。
因为有许可证这种中间介质,也就避免了调用线程不推荐的Thread.suspend()Thread.resume()而导致的线程失活的竟态情况。这里我个人的理解是,线程调度的复杂性和延迟。比如说:线程的休眠和暂停并不能够做到即可马上、命令之间的重排等等。并且,park()也额外支持了线程打断和超时功能。
类的文档里面额外提及了一个惯用法,说的是pack()调用会"无理由"返回,从而导致线程莫名的执行下去。那么惯用法就是把pack()逻辑包装在一个循环当中,并且循环退出的条件就是线程等待同步许可的条件。这就相当于一个自旋的优化,只是需要unpack()配合。

一个阻塞线程的简单范例:

public static void main(String[] args) {    LockSupport.park();    System.out.println("主线程阻塞,并不会打印当前消息");}

一个通用的使用范式:

    public static void main(String[] args) throws InterruptedException {        Thread busThreadJim = new Thread(() -> {            System.out.println("参数检查...");            System.out.println("执行业务逻辑...");            System.out.println("进入状态同步点");            LockSupport.park("因为可能原因A而阻塞住线程");            System.out.println("同步点完成,进步业务收尾阶段...");            System.out.println("进入最后一个同步点结束");            LockSupport.park("报告这个线程当前的工作程度或者状态xxxx");            System.out.println("业务逻辑完成退出");        });        busThreadJim.start();        System.out.println("控制线程或者监控线程开始做其他逻辑...");        Thread.sleep(2000);        System.out.println("检查工作线程是否阻塞住,为什么:" + LockSupport.getBlocker(busThreadJim));        LockSupport.unpark(busThreadJim);        // 如果线程调度慢 LockSupport.getBlocker获取到null        // 也就是说工作线程还没有阻塞住        System.out.println("可以通过阻塞对象来传出一些线程工作信息:" + LockSupport.getBlocker(busThreadJim));        System.out.println("当然共享变量也是可以的");        LockSupport.unpark(busThreadJim);        System.out.println("逻辑完成");    }

多次unpack()也只能消耗一次

    public static void main(String[] args) throws InterruptedException {        Thread worker = new Thread(() -> {            System.out.println("执行业务逻辑...");            System.out.println("进入状态同步点...");            LockSupport.park();            System.out.println("同步点完成,进步业务收尾阶段...");            LockSupport.park();            System.out.println("最后一个同步点结束");        });        worker.start();        LockSupport.unpark(worker);        LockSupport.unpark(worker);        Thread.sleep(2000);        LockSupport.unpark(worker);    }

设计代码逻辑的时候,尽量有明确的阻塞条件,然后选择带有时间截至的函数和提供阻塞信息的对象。
理论上来说,应该用不到这个类。但是一旦用到了,估计就是设计很基础的东西,上面肯定有复杂的逻辑。没有阻塞信息到时候逻辑排查是要命的。

与wait/notify机制的区别

  1. wait/notify必须在同步代码块中使用,光这一点就感觉到限制比较大。

  2. wait/notify操作的是对象,然后才能映射到对象所在的线程,思考方式有点饶。

  3. 复杂的逻辑,特别是嵌套,特别窒息。

源码实现关键点

public class LockSupport {    private LockSupport() {} // 该类无法实例化    // 所有的功能都代理给内部来实现    private static final sun.misc.Unsafe UNSAFE;        // 把当前线程阻塞住    public static void park() {        UNSAFE.park(false, 0L);    }    // 把当前执行线程与一个阻塞对象相关连    // 这样子关注对象就变成线程而非对象    public static void park(Object blocker) {        Thread t = Thread.currentThread();        setBlocker(t, blocker);        UNSAFE.park(false, 0L);        setBlocker(t, null);    }        // 下面就是一系列时间相关函数    public static void parkNanos(Object blocker, long nanos) {        if (nanos > 0) {            Thread t = Thread.currentThread();            setBlocker(t, blocker);            UNSAFE.park(false, nanos);            setBlocker(t, null);        }    }    public static void parkUntil(Object blocker, long deadline) {        Thread t = Thread.currentThread();        setBlocker(t, blocker);        UNSAFE.park(true, deadline);        setBlocker(t, null);    }    public static void parkNanos(long nanos) {        if (nanos > 0)            UNSAFE.park(false, nanos);    }    public static void parkUntil(long deadline) {        UNSAFE.park(true, deadline);    }    // 唤醒目标也是线程 跟阻塞关注点相同    public static void unpark(Thread thread) {        if (thread != null)            UNSAFE.unpark(thread);    }    // 返回阻塞对象信息    // 如果频繁的pack,那么该对象可能一直在变更,它的生命周期会比较短,只是最近一次阻塞的信息    public static Object getBlocker(Thread t) {        if (t == null)            throw new NullPointerException();        return UNSAFE.getObjectVolatile(t, parkBlockerOffset);    }}

值得注意的关注点在于blocker的信息获取,直接操作内存,因为线程已经阻塞住,只能通过这种机制来获取阻塞线程内信息。

"LockSupport的原理和作用是什么"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

线程 阻塞 逻辑 对象 同步 信息 业务 许可证 就是 工作 作用 复杂 条件 状态 原理 也就是 也就是说 代码 关注点 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 软件开发为何这么高工资 安卓源码下载连接数据库 软件开发外包合同补充协议 统一存储服务器 asp清空全部数据库代码 英雄联盟战队服务器怎么升级 上海品质软件开发参考价格 c 数据库链接赋值给ds 阿里聚安全 算法 数据库 c list删选数据库 计算机网络技术考大学好考吗 网络安全软件开发学什么语言 以下不是数据库技术的是 人事管理数据库课程设计 单位电脑网络安全制度 以色列本古里安大学网络安全博士 深蓝科技金盾网络安全 软件开发笔记本用什么配置好 was连接数据库断 1.12数据库肩部板甲 软件开发小程序多少钱 江西iphone服务器托管 北京 能管 软件开发 服务器万能网卡驱动 各种软件开发实例 网络素养跟网络安全一样吗 反潜信息网络技术 海康威视服务器管理密码忘记 新乡市尚嘉网络技术有限公司 永大电梯服务器电源怎么调
0