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…...

面试题. 搜索旋转数组
搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。 示例1: 输入…...

前端需要理解的数据治理与异常监控知识
1 数据治理 前端数据治理的重要指标是准确性和数据,一个数据对象包括数据值和其他元数据。 2 数据上报方式 2.1 Image 通过将采集的数据拼接在图片请求的后面,向服务端请求一个 1*1 px 大小的图片(gif)实现的,设置…...

ip_vs 原理解析 (四)hook 后的开始 一
文章目录 ip_vs hook 后NF_INET_LOCAL_IN 本章重点: k8s 如何利用 ip_vs 实现源 IP 会话亲和性。 ip_vs hook 后 NF_INET_LOCAL_IN 根据优先级依次是 ip_vs_reply4,ip_vs_remote_request4 ip_vs_reply4| -- ip_vs_out| -- skb_to_full_sk(skb…...

【论文解读】基于图的自监督学习联合嵌入预测架构
一、简要介绍 本文演示了一种学习高度语义的图像表示的方法,而不依赖于手工制作的数据增强。论文介绍了基于图像的联合嵌入预测架构(I-JEPA),这是一种用于从图像中进行自监督学习的非生成性方法。I-JEPA背后的idea很简单ÿ…...

C++ 容器
string 1. 构造 string s1(); // 1 string s2("hello"); // hello string s3(3, k); // kkk string s4("hellohello", 2, 4); // lloh2. 赋值 string s1 "hellohello"; // hellohello string s2.assign(s1); // he…...

【PHP】PHP文件操作详解
PHP是一种广泛使用的服务器端脚本语言,用于开发Web应用程序。在PHP中,文件操作是一项重要的功能,包括文件的读取、写入、删除和其他操作。本文将详细介绍PHP文件操作的各个方面,并通过示例代码进行说明。 一、文件读取 要读取一…...

硬核旗舰南卡OE CC开放式耳机发布,重新定义百元开放式耳机新标杆!
随着现在健康意识的不断提高,人们对于日常用品的要求越来越高,在耳机市场中,健康因素也逐渐成为消费者所考虑的因素之一,入耳式耳机因为会引发中耳炎、耳膜炎等疾病,正在逐渐被开放式蓝牙耳机所取代,南卡…...

785. 判断二分图
785. 判断二分图 原题链接:完成情况:解题思路:参考代码: 原题链接: 785. 判断二分图 https://leetcode.cn/problems/is-graph-bipartite/description/ 完成情况: 解题思路: 题目解释&#x…...

限时 180 天,微软为 RHEL 9 和 Ubuntu 22.04 推出 SQL Server 2022 预览评估版
导读近日消息,微软公司今天发布新闻稿,宣布面向 Red Hat Enterprise Linux(RHEL)9 和 Ubuntu 22.04 两大发行版,以预览模式推出 SQL Server 2022 评估版。 近日消息,微软公司今天发布新闻稿,宣布…...

一款ccm的功率因素校正控制器ncp1654
产品概述: NCP1654是用于连续传导模式的控制器(CCM)功率因数校正升压预转换器。它控制固定频率模式下的电源开关导通时间(PWM)并且取决于瞬时线圈电流。 该电路封装在SO8封装中,最大限度地减少了外部组件&a…...