Java并发编程系列之LockSupport的用法
1、什么是LockSupport?
LockSupport是用于创建锁和其他同步类的基本线程阻塞原语
2、两类基本API
LockSupport
提供了两类最基本的API:
block线程类:一般都是以pack开头的方法名,pack*(...)
pack方法有两个重载的版本:blocker是一个对象,用于指定阻塞哪个对象。不知道的情况,默认以锁对象自己this为blocker
public static void park(); public static void park(Object blocker);
拓展:parkNanos
函数
public static void parkNanos(Object blocker, long nanos) { if (nanos > 0) { // 获取当前线程 Thread t = Thread.currentThread(); // 设置Blocker setBlocker(t, blocker); // 获取许可,并设置了时间 UNSAFE.park(false, nanos); // 设置许可,重新设置blocker为null,避免unpack,获取的blocker为之前设置的 setBlocker(t, null); } }
nanos参数表示相对时间,表示等待多长时间
parkUntil
函数:表示在指定的时限前禁用当前线程,deadline参数表示绝对时间,表示指定的时间
public static void parkUntil(Object blocker, long deadline) { // 获取当前线程 Thread t = Thread.currentThread(); // 设置Blocker setBlocker(t, blocker); UNSAFE.park(true, deadline); // 设置Blocker为null setBlocker(t, null); }
unBlock
线程类:unpack(Thread)
unpack方法用于释放许可,指定线程可以继续运行。
3、LockSupport本质
LockSupport是一个许可的信号量机制,pack消费,unpack放入,放入也是仅一个,不累计。例如,调用unpack放入一个信号量,多次调用,这个是不会累计信号量的,pack调用之后会消费
4、LockSupport例子
例子:如何控制两个线程依次打印1、2、3、4、5、6、…
import java.util.concurrent.locks.LockSupport; public class LockSupportExample { private static final int total = 10; private static int i = 0; static Thread t1 , t2; public static void main(String[] args) { t1 = new Thread(() ->{ while (i < total) { System.out.println("t1:" + (++i)); LockSupport.unpark(t2); LockSupport.park(); } }); t2 = new Thread(() -> { while (i < total) { LockSupport.park(); System.out.println("t2:" + (++i)); LockSupport.unpark(t1); } }); t1.start(); t2.start(); } }
打印:
t1: 1
t2: 2
t1:3
t2:4
t1:5
t2:6
t1:7
t2:8
t1:9
t2:10
5、LockSupport源码
public class LockSupport { // Hotspot implementation via intrinsics API 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对象 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); } } }
pack方法的源码:
public static void park(Object blocker) { // 获取当前线程 Thread t = Thread.currentThread(); // 设置Blocker setBlocker(t, blocker); // 获取许可 UNSAFE.park(false, 0L); // 重新可运行后再此设置Blocker为null,避免unpack获取到上一个设置的setBlocker(t, blocker); setBlocker(t, null); }
unpack的源码:
public static void unpark(Thread thread) { if (thread != null) // 线程为不空 UNSAFE.unpark(thread); // 释放该线程许可 }
可以看出,不管是pack的源码还是unpack的源码都是通过Unsafe的底层api实现的
sun.misc.Unsafe
可以直接进行底层非安全操作的工具类
主要提供如下操作:
- 线程挂起与恢复
- CAS操作
- 操纵对象属性
- 操纵数组元素
- 直接操纵内存
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注猪先飞的更多内容!
原文出处:https://smilenicky.blog.csdn.net/article/details/121102818
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
Java中lombok的@Builder注解的解析与简单使用详解
这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06- 下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解
这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- 在Java中,我们可以利用多线程来最大化地压榨CPU多核计算的能力,下面这篇文章主要给大家介绍了关于java中多线程与线程池基本使用的相关资料,需要的朋友可以参考下...2021-09-13