Java并发编程系列之LockSupport的用法
程序员文章站
2022-06-26 09:59:09
目录1、什么是locksupport?2、两类基本api3、locksupport本质4、locksupport例子5、locksupport源码总结1、什么是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操作
- 操纵对象属性
- 操纵数组元素
- 直接操纵内存
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!
下一篇: 没见过撒尿呀
推荐阅读
-
Java日期时间API系列5-----Jdk7及以前的日期时间类TimeUnit在并发编程中的应用
-
JAVA并发编程(三):同步的辅助类之闭锁(CountDownLatch)与循环屏障(CyclicBarrier)
-
Java多线程并发编程中并发容器第二篇之List的并发类讲解
-
Java并发编程锁系列之ReentrantLock对象总结
-
读书笔记之《Java 并发编程的艺术》
-
Java并发编程系列之LockSupport的用法
-
Java并发编程深入理解之Synchronized的使用及底层原理详解 下
-
Java并发编程深入理解之Synchronized的使用及底层原理详解 上
-
Java 8系列之Stream中万能的reduce用法说明
-
Java日期时间API系列5-----Jdk7及以前的日期时间类TimeUnit在并发编程中的应用