Java并发编程之LockSupport类详解
作者:戏子zzz 发布时间:2022-08-21 10:38:36
标签:Java,LockSupport类,并发编程
一、LockSupport类的属性
private static final sun.misc.Unsafe UNSAFE;
// 表示内存偏移地址
private static final long parkBlockerOffset;
// 表示内存偏移地址
private static final long SEED;
// 表示内存偏移地址
private static final long PROBE;
// 表示内存偏移地址
private static final long SECONDARY;
static {
try {
// 获取Unsafe实例
UNSAFE = sun.misc.Unsafe.getUnsafe();
// 线程类类型
Class<?> tk = Thread.class;
// 获取Thread的parkBlocker字段的内存偏移地址
parkBlockerOffset = UNSAFE.objectFieldOffset(tk.getDeclaredField("parkBlocker"));
// 获取Thread的threadLocalRandomSeed字段的内存偏移地址
SEED = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSeed"));
// 获取Thread的threadLocalRandomProbe字段的内存偏移地址
PROBE = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomProbe"));
// 获取Thread的threadLocalRandomSecondarySeed字段的内存偏移地址
SECONDARY = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception ex) { throw new Error(ex); }
}
二、LockSupport类的构造函数
// 私有构造函数,无法被实例化
private LockSupport() {
}
三、park(Object blocker)方法 和 park()方法分析
//调用park函数时,当前线程首先设置好parkBlocker字段,然后再调用 Unsafe的park函数
// 此后,当前线程就已经阻塞了,等待该线程的unpark函数被调用,所以后面的一个 setBlocker函数无法运行
// unpark函数被调用,该线程获得许可后,就可以继续运行了,也就运行第二个 setBlocker
// 把该线程的parkBlocker字段设置为null,这样就完成了整个park函数的逻辑。
// 总之,必须要保证在park(Object blocker)整个函数 执行完后,该线程的parkBlocker字段又恢复为null。
//阻塞当前线程,并且将当前线程的parkBlocker字段设置为blocker
public static void park(Object blocker) {
// 获取当前线程
Thread t = Thread.currentThread();
//将当前线程的parkBlocker字段设置为blocker
setBlocker(t, blocker);
//阻塞当前线程,第一个参数表示isAbsolute,是否为绝对时间,第二个参数就是代表时间
UNSAFE.park(false, 0L);
//重新可运行后再此设置Blocker
setBlocker(t, null);
}
//无限阻塞线程,直到有其他线程调用unpark方法
public static void park() {
UNSAFE.park(false, 0L);
}
四、parkNanos(Object blocker,long nanos)方法 和 parkNanos(long nanos)方法分析
//阻塞当前线程nanos秒 毫秒
public static void parkNanos(Object blocker, long nanos) {
//先判断nanos是否大于0,小于等于0都代表无限等待
if (nanos > 0) {
// 获取当前线程
Thread t = Thread.currentThread();
//将当前线程的parkBlocker字段设置为blocker
setBlocker(t, blocker);
//阻塞当前线程现对时间的nanos秒
UNSAFE.park(false, nanos);
//将当前线程的parkBlocker字段设置为null
setBlocker(t, null);
}
}
//阻塞当前线程nanos秒 毫秒
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
五、parkUntil(Object blocker,long deadline)方法 和 parkUntil(long deadline)方法分析
//将当前线程阻塞绝对时间的deadline秒,并且将当前线程的parkBlockerOffset设置为blocker
public static void parkUntil(Object blocker, long deadline) {
//获取当前线程
Thread t = Thread.currentThread();
//设置当前线程parkBlocker字段设置为blocker
setBlocker(t, blocker);
//阻塞当前线程绝对时间的deadline秒
UNSAFE.park(true, deadline);
//当前线程parkBlocker字段设置为null
setBlocker(t, null);
}
//将当前线程阻塞绝对时间的deadline秒
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
六、setBlocker(Thread t, Object arg)和 getBlocker(Thread t) 方法分析
// 设置线程t的parkBlocker字段的值为arg
private static void setBlocker(Thread t, Object arg) {
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
//获取当前线程的Blocker值
public static Object getBlocker(Thread t) {
//若当前线程为空就抛出异常
if (t == null)
throw new NullPointerException();
//利用unsafe对象获取当前线程的Blocker值
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
七、unpark(Thread thread) 方法分析
//释放该线程的阻塞状态,即类似释放锁,只不过这里是将许可设置为1
public static void unpark(Thread thread) {
// 线程为不空
if (thread != null)
// 释放该线程许可
UNSAFE.unpark(thread);
}
八、LockSupport优点
LockSupport比Object的wait/notify有两大优势
1.LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。
2.unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。
来源:https://blog.csdn.net/weixin_45480785/article/details/116721849


猜你喜欢
- 前言注解(Annotation)不是程序,但可以对程序作出解释,也可以被其它程序(如编译器)读取。注解的格式:以@注释名在代码中存在,还可以
- 本文实例讲述了Spring实战之注入集合值操作。分享给大家供大家参考,具体如下:一 配置<?xml version="1.0
- 一、项目介绍【知识准备】①Android Interface definition language(aidl,android接口定义语言)
- RateLimiter官方文档RateLimiter令牌桶原理图随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是1
- JSON.toJSONString格式化成json字符串时保留null属性使用阿里的com.alibaba.fastjson.JSON格式化
- 一、自动装配1、四种类型的自动装配类型解释xml 配置byName根据 Bean 的 name 或者 id<bean id=”bean
- ArrayList集合的创建非泛型创建ArrayList集合对象,可以添加任意Object子类元素至集合//非泛型创建的ArrayList集
- 前言MVC模式是目前主流项目的标准开发模式,这种模式下框架的分层结构清晰,主要分为Controller,Service,Dao。分层的结构下
- 当我们要创建一个Tcp/Ip Server connection ,我们需要一个范围在1000到65535之间的端口 。但是本机一个端口只能
- 网上查找资料要么是细节不够失败要么是根本没用也不需要这么复杂,在这里总结一下本人在宝塔部署前端和后端的方法。1.在宝塔上添加站点&u
- 声明式事务回顾事务事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!事务管理是企业级应用程序开发中必备技术,用来确保数据的完整
- 本文实例讲述了Android中CountDownTimer倒计时器用法。分享给大家供大家参考,具体如下:在平时我们编程的时候,经常会用到倒计
- 本文实例中的自定义类PictureBox继承于UserControl,最终实现简单的分屏功能。分享给大家供大家参考之用。具体实现代码如下:p
- 双向信号和竞赛(Two-Way Signaling and Races) Monitor.Pulse方法的一个重要特性是它是异步执
- 本文实例讲述了Android编程中Tween动画和Frame动画实现方法。分享给大家供大家参考,具体如下:Animation主要有两种动画模
- 一、先看下项目结构CodeGenerator:生成器主类resources下的mapper.java.vm:一个模板类,用以在生成dao层时
- 今天查看登录日志,发现http_x_forwarded_for获取到的ip地址有些是内网ip地址,有些则是公网和内网ip地址一起获取到,用逗
- 用类加载器的5中形式读取.properties文件(这个.properties文件一般放在src的下面)用类加载器进行读取:这里采取先向大家
- 来源:https://www.cnblogs.com/fanweisheng/p/11440
- 前言想使用ffmpeg打开摄像头,需要输入摄像头的名称,而ffmpeg本身的枚举摄像头列表功能不是接口,所以需要用其他方式获取到设备列表。C