Java并发编程系列之LockSupport的用法

网友投稿 250 2022-09-13


Java并发编程系列之LockSupport的用法

目录1、什么是LockSupport?2、两类基本API3、LockSupport本质4、LockSupport例子5、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(() ->{

http:// 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可以直接进行底层非安全操作的工具类

主要http://提供如下操作:

线程挂起与恢复

CAS操作

操纵对象属性

操纵数组元素

直接操纵内存

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:自己搭建自动化巡检系统(四) 处理邻居列表(自动巡边系统)
下一篇:网段、子网和掩码(子网掩码相同是一个网段吗)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~