JUC工具类-LockSupport概述
前言
多线程并发场景中,时常需要线程协同,故而需要对当前线程进行阻塞,并唤醒需要协同的线程来一起完成任务。
通常处理方式有三种:
1)Synchronized加锁的线程
使用Object类下所提供的方法:
- wait():让当前线程处于等待状态,并释放当前拥有的锁;
- notify():随机唤醒等待该锁的其他线程,重新获取锁,并执行后续的流程,只能唤醒一个线程;
- notifyAll():唤醒所有等待该锁的线程(锁只有一把,虽然所有线程被唤醒,但所有线程需要排队执行)
2)Lock加锁的线程
Condition 类下的锁提供的方法:
- await():对应 Object 的 wait() 方法,线程等待;
- signal():对应 Object 的 notify() 方法,随机唤醒一个线程;
- signalAll():对应 Object 的 notifyAll() 方法,唤醒所有线程。
3)以上两种加锁的场景
使用JUC中LockSupport阻塞工具类的方法:
- LockSupport.park():休眠当前线程。
- LockSupport.unpark(线程对象):唤醒某一个指定的线程。
概述
LockSupport来自于JDK1.5,位于JUC包的locks子包,是一个非常方便实用的线程阻塞工具类,它定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,可以在线程内任意位置让线程阻塞、唤醒。
在AQS框架的源码中,当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具来完成。LockSupport 和 CAS 是Java并发包中并发工具(锁和其他同步类)控制机制的实现基础,而这两个基础其实又是依赖Unsafe类,然而Unsafe只是维护了一系列本地方法接口,因此真正的实现是在HotSpot的源码中,而HotSpot是采用C++来实现的!
AQS框架是JUC中实现同步组件的基石,而LockSupport可以说是AQS框架的基石之一。
LockSupport的特征和原理
特征
1、LockSupport是非重入的。因为调用一次park方法,线程就被阻塞了。
**2、LockSupport的park阻塞、unpark唤醒的调用不需要任何条件对象,也而不需要先获取什么锁。**也就是说LockSupport只与线程绑定,就可以降低代码耦合性。
**3、park阻塞与unpark唤醒的调用顺序可以颠倒,不会出现死锁,并且可以重复多次调用unpark。**但是ThreadGroup类的stop和resume方法如果顺序反了,就会出现死锁现象。
**4、park支持中断唤醒,但是不会抛出InterruptedException异常。**意思就是使用Thread.interrupted() 可以使线程中断,会使park失效。
原理
每个线程都与一个许可(permit)关联。unpark函数为线程提供permit,线程调用park函数则等待并消耗permit。permit默认是0,调用一次unpark就变成1,再调用一次park会消费permit,也就是将1变成0,park会立即返回。
如果原来没有permit,那么调用park会将相关线程阻塞在调用处,等待一个permit,这时调用unpark又会把permit置为1,使得阻塞的线程被唤醒。每个线程都有自己的permit,但是permit最多持有一个,重复调用unpark也不会积累。
LockSupport.park和LockSupport.unpark不会引发的死锁问题,因为由于许可的存在,即使unpark发生在park之前,也可以使得下一次的park操作立即返回。
和Object.wait相比,LockSupport.park不需要先获得某个对象的锁,也不会抛出InterruptedException 异常。
和synchronized相比,LockSupport.park()阻塞的线程可以被中断阻塞,但是不会抛出异常,并且中断之后不会清除中断标志位。被park阻塞的线程处于WAITING状态,超时park阻塞的线程则处于TIMED_WAITING状态。
LockSupport的方法解析
LockSupport定义了一组以park开头的方法用来阻塞当前线程,以及unpark方法来唤醒一个被阻塞的线程。
park
除非许可证permit可用,否则出于线程调度目的禁用当前线程。 如果许可证可用,则该许可证被消耗,呼叫立即返回;否则,出于线程调度目的,当前线程将被禁用,并处于休眠状态,直到发生以下三种情况之一:
- 其他线程以当前线程为目标调用 unpark;
- 或其他线程中断当前线程;
- 或呼叫错误地(即,没有原因地)返回。
此方法不报告导致方法返回的原因。调用方应首先重新检查导致线程停止的条件。调用方还可以在返回时确定线程的中断状态。
unpark
使给定线程的许可证permit可用(如果尚未可用)。如果线程在 park上被阻塞,那么它将解除阻塞。否则,它对 park 的下一次呼叫保证不会被阻塞。如果给定的线程尚未启动,则不能保证此操作有任何效果。
源码分析
在 LockSupport.park()的底层主要是调用 Unsafa 类的 park方法,每个线程对象都有一个 Parker 实例,这个实例内部有提供park和unpark方法。
Unsafe类
Unsafe这个类中有许多的native方法,通过字段偏移量(类似于C的指针),提供了Java语言与底层系统进行交互的接口,通过Unsafe可以直接操作底层系统,它具有直接内存管理、线程阻塞&唤醒的支持、CAS操作的支持、直接操作类、对象、变量等强大的功能。
JavaThread
JavaThread内部具有一个threadOb属性,这个属性实际上就是保存这着Java层面的一个Thread对象,而JavaThread继承了Thread,继承了_osthread字段。那么一个JavaThread对象和一个OSThread对象对应,同时又和一个Thread对象对应,这样它们三个的就被联系起来了。因此实际上一个Java的Thread对应着一个OS线程。
Unsafe可以直接操作JVM和底层系统,因此,可以通过Thread是直接找到JavaThread实例进行操作,因此即使我们在Thread中没有找到“permit”,但是这个“permit”肯定是在Hotspot的源码中能就见到!
JavaThread内部还有一个Parker类型的_parker属性,这个Parker实际上就是用来实现Java中的LockSupport 的park 和unpark的,即实现单个线程的阻塞和唤醒,也就是JUC的中线程阻塞、唤醒在JVM层面的实现。
Parker有一个_counter字段,这个字段实际上就是我们常说的“许可”,并且默认初始化为0。我们调用的park、unpark方法,实际上是调用的Parker的同名方法。
PlatformParker
Parker源码中表示Parker继承了PlatformParker,由于Hotspot虚拟机为跨平台,针对不同操作系统有不同的实现,最常见的就是linux系统,以此来分析。
PlatformParker内部具有POSIX库标准的互斥量(锁)mutex和条件变量condition,那么实际上Parker的对于park和unpark的实现实际上就是用这两个工具实现的。
另外,PlatformParker还有一个cur_index属性,它的值为-1、0或者1,-1时初始化的值,调用park并返回的线程也会设置值为-1。如果不是-1,那么表示对应的parker中的条件变量上有线程被挂起,_cur_index等于0表示调用park相对时间的线程在第一个条件变量上被挂起,等于1则表示调用park绝对时间的线程在第二个条件变量上被挂起。
mutex与condition概述
实际上mutex与condition都是posix标准的用于底层系统线程实现线程同步的工具。 mutex被称为互斥量锁,类似于Java的锁,即用来保证线程安全,一次只有一个线程能够获取到互斥量mutex,获取不到的线程则可能会阻塞。而这个condition可以类比于java的Condition,被称为条件变量,用于将不满足条件的线程挂起在指定的条件变量上,而当条件满足的时候,再唤醒对应的线程让其执行。
可以理解为,mutex与condition来实现加锁、释放锁。如同synchronized与监视器对象一样。
Parker 和 Synchronized的ParkEvent 的区别
ParkEvent是用于Java级别的Synchronized关键字,Parker是JSR166来的并发工具集合,后面会统一使用ParkEvent。ParkerEvent 继承了PlatformEvent,基类PlatformEvent是特定于平台的,而ParkEvent则是平台无关的。而Parker 继承自PlatformParker。
- ParkerEvent中的park,unpark方法用于实现Java的object.wait()方法和object.notify()方法;
- Parker中的park,unpark方法用于实现Java的Locksupprt.park()方法和Locksupprt.unpark()方法;
park 方法源码分析
执行过程:
1、判断是否需要阻塞等待,如果已经是 _counter >0, 不需要等待,将 _counter = 0 , 返回
2、如果 1 不成立,构造当前线程的 ThreadBlockInVM ,检查 _counter > 0 是否成立,成立则将 _counter 设置为 0, unlock mutex 返回;
3、如果 2 不成立,更具需要时间进行不同的函数等待,如果等待正确返回,则将 _counter 设置为0, unlock mutex , park 调用成功。
parker 类的定义如下
- Parker 类继承 os::PlatformParker。
- 有一个 _counter 属性,可以理解为是否可以调用 park 方法的许可证,只有 _count > 0 的时候才能调用;
- 提供了公开的 park 和 unpark 方法
unpark 方法源码分析
执行过程:
- pthread_mutex_lock 获取锁
- _counter 设置为 1
- 判断 _counter 的旧值:
- 小于 1 时,调用 pthread_cond_signal 唤醒在 park 阻塞的线程;
- 等于 1 时,直接返回
总结
LockSupport是JDK1.5时提供的用于实现单个线程等待、唤醒机制的阻塞工具,也是AQS框架的基石之一,另外两个则是CAS操作、volatile关键字。
每个Java线程内部,其对应着OS线程,而对线程的操作,也就是对于操作系统的操作。JDK提供Unsafe类可以直接操作底层系统,它本身具有直接内存管理、线程阻塞&唤醒的支持、CAS操作的支持、直接操作类、对象、变量等强大的功能。Unsafe类关于线程阻塞、唤醒,有提供Parker类,Parker类继承PlatformParker。
PlatformParker内部具有POSIX库标准的互斥量(锁)mutex和条件变量condition,那么实际上Parker的对于park和unpark的实现实际上就是用这两个工具实现的。
LockSupport.park方法实质上就是调用了Unsafe类的Native方法,执行LockSupport.park方法不会释放此前获取到的synchronized锁或者lock锁,因为LockSupport的方法根本就与我们常说的“锁”无关。其本质依赖了mutex和Condition工具。
相关文章:
JUC工具类-LockSupport概述
前言 多线程并发场景中,时常需要线程协同,故而需要对当前线程进行阻塞,并唤醒需要协同的线程来一起完成任务。 通常处理方式有三种: 1)Synchronized加锁的线程 使用Object类下所提供的方法: wai…...

大数据:AI大模型对数据分析领域的颠覆(文末送书)
随着数字化时代的到来,大数据已经成为了各行各业中不可或缺的资源。然而,有效地分析和利用大数据仍然是一个挑战。在这个背景下,OpenAI推出的Code Interpreter正在对数据分析领域进行颠覆性的影响。 如何颠覆数据分析领域?带着这…...

CEdit 选中文字实时更新到另一个控件中
有时候,我们会遇到需求,软件中需要让选中一个CEdit控件中的文字实时更新到另一个控件中,实现效果如下所示: 代码如下: BOOL CEditDemoDlg::PreTranslateMessage(MSG* pMsg) { CEdit* pOldEdit (CEdit*)GetDlgIte…...

Word导出创建Adobe PDF其中emf图片公式马赛克化及文字缺失
软件版本 Word 2021 Visio 2019 Adobe Acrobat Pro 2020 问题描述 公式马赛克化,是指在Word中使用MathType编辑的公式,然后在Visio中使用图片(增强型图元文件)形式得到的粘贴对象,效果如下 文字缺失,是指Word导出→创建Adobe P…...

[matlab]matlab配置mingw64编译器
第一步:下载官方绿色版本mingw64编译器然后解压放到一个非中文空格路径下面 比如我mingw64-win是我随便改的文件名,然后添加环境变量,选择用户或者系统环境变量添加下面的变量 变量名: MW_MINGW64_LOC 变量值:自己的m…...
华为OD-非严格递增连续数字序列
题目描述 输入一个字符串仅包含大小写字母和数字 求字符串中包含的最长的非严格递增连续数字序列长度 比如: 12234属于非严格递增数字序列 输入描述 输入一个字符串仅包含大小写字母和数字 输出描述 输出字符串中包含的最长的非严格递增连续数字序列长度 示例…...

css滚动条样式这样修改下很漂亮
<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>滚动条样式修改下很漂亮(不支持IE)</title> <style type"text/css"> * { margin: 0; padding: 0; } .box { width: 300px; height: 100px; margin…...

转置卷积的应用
目录 矩阵转置 一、转置卷积的背景 二、转置卷积的应用 三、转置卷积的区别 卷积 矩阵转置 矩阵的转置在信息处理中起到了重要的作用。在计算机科学领域,矩阵常用于表示图像、音频和视频等多媒体数据。当我们需要对这些数据进行处理时,常常需要进行…...

常见的移动端布局
流式布局(百分比布局) 使用百分比、相对单位(如 em、rem)等来设置元素的宽度,使页面元素根据视口大小的变化进行调整。这种方法可以实现基本的自适应效果,但可能在不同设备上显示不一致。 <!DOCTYPE ht…...

Typore 亲测有效(懂得都懂哈)
Typore 亲测从安装到使用,可以使用(具体是什么懂得都懂哈) 网盘下载地址:链接:https://pan.baidu.com/s/1w0UiS1szxnO9Lxz6sbXEKg?pwdqwe1 提取码:qwe1 第一步: 下载压缩包进行解压,解压过…...

Kyligence Copilot 登陆海外,斩获 Product Hunt 日榜 TOP 2
8月14日,AI 数智助理 Kyligence Copilot 在全球知名科技产品平台 Product Hunt 上线,其以出色的产品创新实力,在激烈的竞争中脱颖而出,仅仅在 24 小时内收获了超过 400 个投票和近 200 条支持评论,荣登当日产品榜排名第…...
【Docker】Docker 的基本概念和优势,基本命令及使用例子
Docker 是一种轻量级的容器化解决方案,能够快速地创建、部署和运行应用程序。以下是一些 Docker 的基本概念和优势: 基本概念: 1.镜像:一个 Docker 镜像是一个可执行的文件,其中包含了运行应用程序所需要的一切。 2.容…...
高并发内存池(回收)[4]
threadcache还给centralcache void ThreadCache::Deallocate(void* ptr, size_t size) {assert(ptr);assert(size < MAX_BYTES);// 找对映射的自由链表桶,对象插入进入size_t index SizeClass::Index(size);_freeLists[index].Push(ptr);// 当链表长度大于一次…...

分布式事务篇-2.4 Spring-Boot整合Seata
文章目录 前言一、pom jar导入:二、项目配置:2.1 配置 说明:2.1 .1 seata server 端:2.1 .2 seata client 端: 2.2 开启seata 对于数据源的代理:2.3 seata-client 的注册中心:2.4 seata-client 的配置中心:2.5 去掉手写的数据源代…...

718. 最长重复子数组
718. 最长重复子数组 原题链接:完成情况:题解:方法一:动态规划方法二:滑动窗口方法三:二分查找 哈希 原题链接: 718. 最长重复子数组 https://leetcode.cn/problems/maximum-length-of-repe…...

Mysql join加多条件与where的区别
最近在项目中遇到一个问题,感觉有点意思,在解决问题及查阅了相关资料后,打算写篇文章给朋友们分享一下。 问题现象: 问题是很常见的空指针问题,后端查询数据库数据,遍历进行相关业务处理时报空指针。通过…...
div滚动条自动滚动到底部
<div id"center"></div>// 滚动条到最底部scrollToBottom(){var box document.getElementById(center);this.$nextTick(() > {box.scrollTop box.scrollHeight})},...

【深度学习】实验02 鸢尾花数据集分析
文章目录 鸢尾花数据集分析决策树K-means 鸢尾花数据集分析 决策树 # 导入机器学习相关库 from sklearn import datasets from sklearn import treeimport matplotlib.pyplot as plt import numpy as np# Iris数据集是常用的分类实验数据集, # 由Fisher, 1936收集…...

AI大模型潮水中,医疗数字化加速「求解」
蝴蝶挥动翅膀,医疗行业每个角落开始连锁反应,曾经被忽视的问题也愈发明显。但与之对应的是,对数字化和AI大模型的价值认可,在中国医疗赛道也正在加速来临。 作者|斗斗 编辑|皮爷 出品|产业家 重庆市某地方人民医院…...

【安卓】自定义View实现画板涂鸦等功能
一、实现效果 二、代码 1、MainActivity.class package com.lsl.mydrawingboarddemo;import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat;import android.os.Bundle; import android.os.Handler; import android.view.View; impo…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...

华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...