Java并发编程系列之LockSupport的用法
作者:smileNicky 发布时间:2022-04-07 06:48:58
目录
1、什么是LockSupport?
2、两类基本API
3、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(() ->{
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
猜你喜欢
- 一、 搭建struts2环境在myeclipse下,右击项目->MyEclipse->Project Facets->in
- MainActivity.java package com.zhang.showPhoto;import android.app.Actio
- P代表(Profiles配置文件)在<profiles>指定的<id>中,可以通过-P进行传递或者赋值。假如pom.
- 简单的日历实现,只是显示了每一个月,没有显示当天和记事这些功能主要是计算月初是周几,月末是周几,然后相应的显示上一月多少天和下一月多少天。先
- 内存模型Flink可以使用堆内和堆外内存,内存模型如图所示:flink使用内存划分为堆内内存和堆外内存。按照用途可以划分为task所用内存,
- 前言开发传统Java WEB工程时,我们可以使用JSP页面模板语言,但是在SpringBoot中已经不推荐使用了。SpringBoot支持如
- 本文实例讲述了C#在RichTextBox中显示不同颜色文字的方法。分享给大家供大家参考。具体实现方法如下:#region 日志记录、支持其
- 这里用到一个HTML解析辅助类:HtmlAgilityPack,如果没有网上找一个增加到库里,这个插件有很多版本,如果你开发环境是使用VS2
- 1.新建springBoot项目在前面有两种方式2.加入thymeleaf模板引擎SpringBoot推荐使用thymeleaf模板引擎语法
- 本文实例讲述了java实现的简单猜数字游戏代码。分享给大家供大家参考。具体代码如下:import java.util.InputMismat
- 前言由于业务需要,后端需要返回一个树型结构给前端,包含父子节点的数据已经在数据库中存储好,现在需要做的是如何以树型结构的形式返给给前端。数据
- java 引用类型的数据传递的是内存地址java中引用类型的数据,传递的是内存地址,像类,数组,接口,String等等都是引用类型!看下面的
- 本文实例为大家分享了JAVA NIO实现简单聊天室功能的具体代码,供大家参考,具体内容如下服务端初始化一个ServerSocketChann
- 局限性只支持MP4文件经过尝试对于一些MP4文件分割不了依赖<!-- mp4文件操作jar --><!-- https:/
- Android自定义view是什么在我们的日常开发中,很多时候系统提供的view是无法满足我们的需求的,例如,我们想给一个edittext加
- 描述说明:public class TryCatchStu { /*try catch:自己处理异常 *t
- Spring Boot 自动装配最重要的注解@SpringBootApplication@Target(ElementType.TYPE)@
- pom.xml文件需要的内容<dependency> <groupId>re
- 1、下载源代码点击这个链接:http://www.scala-lang.org/download/all.html选择需要的版本点击打开;在
- 最近由于项目需要把不同格式的视频转换为ts流,故研究了一下ffmpeg。在网上找了很多资料,主要参考了Java+Windows+ffmpeg