【JavaEE】多线程进阶
🤡🤡🤡个人主页🤡🤡🤡
🤡🤡🤡JavaEE专栏🤡🤡🤡
文章目录
- 1.锁策略
- 1.1悲观锁和乐观锁
- 1.2重量级锁和轻量级锁
- 1.3自旋锁和挂起等待锁
- 1.4可重入锁和不可重入锁
- 1.5公平锁和非公平锁
- 1.6互斥锁和读写锁
- 2.synchronized的实现原理
- 2.1实现过程
- 2.2偏向锁
- 2.3优化策略
- 2.3.1锁升级
- 2.3.2锁消除
- 2.3.3锁粗化
- 3.CAS
- 3.1什么是CAS
- 3.2CAS的应用
- 3.2.1原子类
- 3.2.2实现自旋锁
- 3.3CAS的ABA问题
- 3.3.1ABA问题
- 3.3.2ABA引起的BUG
- 3.3.3如何避免由ABA问题引起的BUG
- 4.java.util.concurrent常见类
- 4.1Callable接口
- 4.2ReentrantLock类
- 4.2.1发音
- 4.2.2ReentrantLock的关键特性与功能
- 4.3Semaphore类——信号量
1.锁策略
1.1悲观锁和乐观锁
区别:加锁的时候,预测当前锁冲突的概率是大还是小
悲观锁:预测当前锁冲突概率大,后续要做的工作往往就会更多,加锁的开销(时间,系统资源)就更大。
乐观锁:预测当前锁冲突概率小,后续要做的工作往往就会更少,加锁的开销(时间,系统资源)就更小。
注意:悲观锁往往通过内核来完成操作的,所以做的工作多,乐观锁往往通过用户完成操作的,所以做的工作少。
1.2重量级锁和轻量级锁
这两个锁和上述的悲观锁和乐观锁有着很大的关系,一般悲观锁就是重量级锁,因为悲观锁做的任务多,那么就需要很大的开销所以就是重量级锁,反之乐观锁做的任务少,那么开销就少那么就是轻量级锁。
注意:一般这两个锁和上述两个锁都混着用,之所以有区别是因为出发点不一样。
1.3自旋锁和挂起等待锁
自旋锁:锁未被释放之前,cpu会一直空转和忙等,但等锁被释放之后就会立马获取到锁,自旋锁是实现轻量级锁典型的案例。
挂起等待锁:当出现锁冲突,那么要加锁的这个线程就会被挂起等待,此时的线程就不会参与调度,直到这个锁被释放,然后系统内核才唤醒这个线程,去尝试获取锁,拿锁的速度很慢,挂起等待锁是实现重量级锁的典型案例。
1.4可重入锁和不可重入锁
可重入锁:针对一个线程,可以连续加锁两次不会出现死锁,synchronized就是可重入锁。
不可重入锁:针对一个线程,连续加锁两次会出现死锁。像c++中的std::mutex就是不可重入锁
1.5公平锁和非公平锁
公平锁:严格按照先来后到的顺序来获取锁,哪个线程等待的时间长,哪个线程就拿到锁
非公平锁:若干个线程,各凭本事,随机获取锁和线程等待时间无关,synchronized就是一个非公平锁。
系统调度本来就是随机的,如果想实现一个公平锁,那么就需要引入一个特殊的队列来根据线程等待的时间来出队列。
1.6互斥锁和读写锁
互斥锁:加锁和解锁,synchronized就是一个互斥锁
读写锁:加读锁和加写锁,读与读之间不会产生互斥,写与写之间会产生互斥,读与写之间也会产生互斥,
2.synchronized的实现原理
2.1实现过程
未加锁(无锁状态)——>偏向锁——>轻量级锁——>重量级锁
2.2偏向锁
首次使用sychronized对对象加锁,此时并不是真正的加锁而是做了一个标记(非常轻量非常快,几乎没有开销)
如果在这其中没有其他线程对这个对象加锁,那么就一直保持这样的一个状态直到解锁的时候(解锁也只是修改标记,几乎没有开销)
但是如果在这期间,有其他对象对进行加锁,那么就会立马升级成轻量级锁。
注意:在这个升级过程中,是不可逆的,一旦升级了就不能降级(在目前版本的JVM中)
2.3优化策略
2.3.1锁升级
2.3.2锁消除
当你在这个代码中加了锁,编译器和JVM会检查当前代码需不需要加锁,不需要就会将这个锁帮你消除,这是在内部操作的,程序猿是感知不到的,例如我在单线程中加了锁,那么编译器和JVM就会把这个锁给消除。
2.3.3锁粗化
在有些逻辑中,需要频繁加锁和解锁,编译器就会自动把这些多次细粒度的锁合成一次粗粒度的锁,"粒度"是指加锁范围中代码的多少,代码越多粒度就越粗,反之越细。
3.CAS
3.1什么是CAS
CAS这是一个比较交换指令,而且这一指令详细的就是读取内存,比较是否相等,修改内存三个步骤,而与之前线程安全问题中多个线程对同一个变量进行修改操作是一样的,也是上述这三个步骤,但CAS这三个步骤是打包一起的是原子的,而对变量修改不是原子的,所以需要加锁,才能保证线程安全,所以CAS在某种程度也可以实现锁的功能。
3.2CAS的应用
3.2.1原子类
标准库中提供了 java.util.concurrent.atomic 包, ⾥⾯的类都是基于这种⽅式来实现的. 典型的就是 AtomicInteger 类.
通过方法来实现变量的算术运算
//count++
count.getAndIncrement();
//++count
count.incrementAndGet();
//count--
count.getAndDecrement();
//--count
count.decrementAndGet();
//count += 10
count.getAndAdd(10);
通过CAS实现两个线程对count变量相加
AtomicInteger count = new AtomicInteger(0);
Thread t1 = new Thread(()-> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();}
});
Thread t2 = new Thread(()-> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count = " + count);
这种编程方式也称为无锁编程,这种方式可以提高效率,但适用范围不大。
3.2.2实现自旋锁
由于在读取内存,比较相等,修改内存这三个步骤是原子,所以在某种程度上可以实现锁的功能
以下就是一段伪代码简单实现一下自旋锁
class SpinLock{public Thread owner = null;public void lock() {while(!CAS(this.owner,null,Thread.currentThread())) {}}public void unlock() {this.owner = null;}
}
在这个方法中,owner变量如果是null,那么此时就是未加锁状态,那么CAS方法就返回true,取反则为false,退出循环,此时就是未加锁,但当owner这个变量不为null的时候调用CAS方法的线程就会将该对象的引用赋值给this.owenr,这个操作是原子的,所以不会有线程安全问题,从侧面就可以体现相当于对这个线程加锁,从此实现了锁的功能。
3.3CAS的ABA问题
3.3.1ABA问题
假设此时我有两个线程分别为t1和t2线程,还有一个共享变量num,此时t1线程想要通过CAS编码的形式把num原来的值A改为C,但是在这个操作之中,t2线程将num中的值从A改为B,又从B改为A,但是在这期间,t1线程不知道。
3.3.2ABA引起的BUG
比如,有一个cs中的悍匪玩家刚好现在余额还有17元买一个钥匙开个箱子,在购买的过程中,因为网络的波动,他按了两次购买键,导致启动了两个线程去完成这个任务,那么t1线程在购买的时候,t2线程在等待阻塞,t1线程完成了购买获得了一把钥匙,但在t2线程执行前刚好另一个ct好友给这位悍匪玩家充值了17元,导致t2线程在执行的时候发现余额中还有17元,则又帮悍匪玩家买了一把,此时就出现了bug,这个时候买了两把钥匙就是ABA问题引起的。
3.3.3如何避免由ABA问题引起的BUG
在要修改的值加入一个版本号,在CAS比较数据的时候比较当前值和之前要修改的值,也要比较版本号是否相同
CAS操作在读取之前要修改的值的同时,也要读取版本号
真正到修改的时候:
如果当前读的版本号与之前要修改的版本号相同,则修改数据并且修改版本号
如果当前读的版本号与之前要修改的版本号不相同,则视为修改失败(可以认为该数据被修改过)
将这个思路带到悍匪玩家买钥匙的案例中:
- 购买钥匙需要17余额,t1和t2线程获取的余额是17,版本号都是1
- t1线程购买成功之后,余额变为0,版本号变为2,此时t2线程再阻塞等待
- 在t2线程执行前,悍匪玩家的好友ct兄弟为其充值了17元余额,此时账户余额又变为17,但此时版本号为3
- 到t2线程执行的时候,发现余额是17,和之前读到的余额是一样,但是版本号不一样,第一次读的是1,但现在读的是3,版本号不同,则可以视为操作失败
4.java.util.concurrent常见类
4.1Callable接口
这个接口里有个叫call()方法,这个方法与Runnable接口中的run()方法其实大同小异,只是前者有个返回值
在Java中,Thread类的构造方法不直接接受一个Callable对象作为参数。,则需要另一个类来作为一个媒介,FutureTask作为一个媒介。
public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Integer> callable = new Callable<Integer>() {int sum = 0;@Overridepublic Integer call() throws Exception {for (int i = 1; i < 1000; i++) {sum += i;}return sum;}};FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask);thread.start();thread.join();System.out.println("sum = " + futureTask.get());
}
4.2ReentrantLock类
4.2.1发音
ReentrantLock
4.2.2ReentrantLock的关键特性与功能
- ReentrantLock提供了公平锁的实现
- ReentrantLock提供了tryLock操作,该操作会立即返回,是否获取到锁,这对于避免死锁和实现超时机制非常有用。
- ReentrantLock搭配了Condition类完成等待通知,Condition比wait和notify更强点,Condition可以指定阻塞线程唤醒
4.3Semaphore类——信号量
信号量就是一个计数器,计系统资源的个数。
在底层中对信号量的两个基本操作分别为P操作和V操作
P操作——申请资源
V操作——释放资源
在java中JVM将这两个操作分别封装成acquire(申请资源),release(释放资源)
相关文章:

【JavaEE】多线程进阶
🤡🤡🤡个人主页🤡🤡🤡 🤡🤡🤡JavaEE专栏🤡🤡🤡 文章目录 1.锁策略1.1悲观锁和乐观锁1.2重量级锁和轻量级锁1.3自旋锁和挂起等待锁1.4可…...
大模型LLM面试常见算法题-包括Attention和Transformer常见面试题
大模型: 位置编码有哪些? 介绍LoRA与QLoRA RAG和微调的区别是什么? 哪些因素会导致LLM的偏见? 什么是思维链(CoT)提示? Tokenizer的实现方法及原理 解释一下大模型的涌现能力?…...

90元搭建渗透/攻防利器盒子!【硬件篇】
前言 以下内容请自行思考后进行实践。 使用场景 在某些情况下开软件进行IP代理很麻烦,并不能实现真正全局,而且还老容易忘记,那么为了在实景工作中,防止蓝队猴子封IP,此文正现。 正文 先说一下实验效果࿱…...

用vue2+elementUI封装手机端选择器picker组件,支持单选、多选、远程搜索多选
单选注意点: touchmove.prevent: 在 touchmove 事件上添加 .prevent 修饰符,以阻止默认的滚动行为。 handleTouchStart: 记录触摸开始的 Y 坐标和当前的 translateY 值。 handleTouchMove: 计算触摸移动的距离,并更新 translateY 值。 han…...

『古籍自有答案』古风H5案例赏析
「古籍自有答案」,一部由新京报与字节跳动公益联合打造的古风H5,以诗意盎然的开篇引领用户穿梭于千年文脉。 part1. 创意定位 "人生有惑问先贤,先贤答案存古籍",在这里,每一个灵魂的探问,都能在…...
Laravel模型事件完全指南:触发应用程序的动态行为
标题:Laravel模型事件完全指南:触发应用程序的动态行为 在Laravel框架中,模型事件提供了一种优雅的方式来处理Eloquent模型生命周期中的各种关键时刻。通过监听和响应这些事件,开发者可以自动化许多常见的任务,如日志…...
hot100 |八、二叉树
1-leetcode94. 二叉树的中序遍历 注意:√ 递归方法已经很熟练了,两种不同的递归方式迭代法需要注意,zrm就遇到了要求迭代实现,前序遍历和后续遍历其实不难,中序遍历用的少,注意看一看 // 1.递归方法1Lis…...

Matlab协方差矩阵分解法生成随机场
Matlab协方差矩阵分解法生成随机场 相关系数矩阵 % function outcohesion(x,y,mu,theta) % end % xyload(F:\Research-OUC\基于机器许学习模型的海底斜坡可靠度研究\基于comsol的斜坡稳定性分析\comsol网格操作\grid_operate-matlab.mphtxt); % xxy(:,1); % yxy(:,2); Xlinspac…...
android 在清单文件中配置receiver,系统是何时会注册此广播接收者的?
在 Android 中,通过清单文件(AndroidManifest.xml)配置的广播接收器(BroadcastReceiver),系统会在特定的时机自动注册这些广播接收器。以下是详细的说明: 静态注册的广播接收器 静态注册的广播…...
嵌入式硬件电路常用设计软件
目录 1. Cadence Allegro 2. PADS 3. Altium Designer 4. Multisim 5. Protues 1. Cadence Allegro 功能: Cadence Allegro是Cadence公司推出的先进PCB(Printed Circuit Board,印刷电路板)设计布线工具,也是目前…...
c#的List<T>的SelectMany 和Select
在C#中,List<T>(以及任何实现了IEnumerable<T>的集合)的Select和SelectMany扩展方法都是LINQ(Language Integrated Query)的一部分,用于对集合中的元素进行查询和转换。 尽管它们的作用有些相…...

69.WEB渗透测试-信息收集- WAF、框架组件识别(9)
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:68.WEB渗透测试-信息收集- WAF、框架组件识别(8) 有无waf存在&am…...

ASCII码对照表(Matplotlib颜色对照表)
文章目录 1、简介1.1 颜色代码 2、Matplotlib库简介2.1 简介2.2 安装2.3 后端2.4 入门例子 3、Matplotlib库颜色3.1 概述3.2 颜色图的分类3.3 颜色格式表示3.4 内置颜色映射3.5 xkcd 颜色映射3.6 颜色命名表 4、Colorcet库5、颜色对照表结语 1、简介 1.1 颜色代码 颜色代码是…...

Mysql-常用函数及其用法总结
1、字符串函数 测试用例如下: 1.1 CONCAT() 将多个字符串连接成一个字符串。 SELECT CONCAT(first_name, , last_name) AS full_name FROM users; -- 期望结果:John Doe, Jane Smith, Michael Johnson 1.2 SUBSTRING() 提取子字符串 SELECT SUBSTR…...

【c++刷题笔记-数组】day29:452. 用最少数量的箭引爆气球、 435. 无重叠区间 、 763.划分字母区间
452. 用最少数量的箭引爆气球 - 力扣(LeetCode) 思路:先按照左边界排序,当前的左边界大于前一个的右边界的时候,表示没有覆盖所以需要一根箭,反之则要更新为最小的右边界 重点:是区间覆盖问题…...

【数据结构】链表带环问题分析及顺序表链表对比分析
【C语言】链表带环问题分析及顺序表链表对比分析 🔥个人主页:大白的编程日记 🔥专栏:C语言学习之路 文章目录 【C语言】链表带环问题分析及顺序表链表对比分析前言一.顺序表和链表对比1.1顺序表和链表的区别1.2缓存利用率&#…...

快速解决找不到krpt.dll,无法继续执行代码问题
对于那些遇到计算机开机出现由于无法找到krpt.dll,进而无法继续执行代码问题的用户。 krpt.dll是计算机系统中与DirectX紧密相关的重要文件,如果它出现问题,可能会对一些特定的软件或游戏的运行产生影响。实际上,我们有多种解决该…...
C# List、LinkedList、Dictionary性能对比
数据结构性能对比 List、LinkedList、Dictionary 1. ArrayList (List:前传) ArrayList 是一个特殊数组, 通过添加和删除元素就可以动态改变数组的长度。 ArrayList集合相对于数组的优点: 支持…...

【Spring Cloud】微服务的简单搭建
文章目录 🍃前言🎄开发环境安装🌳服务拆分的原则🚩单一职责原则🚩服务自治🚩单向依赖 🍀搭建案例介绍🌴数据准备🎋工程搭建🚩构建父子工程🎈创建父…...

全球首款商用,AI为视频自动配音配乐产品上线
近日,海外推出了一款名为Resona V2A的产品,这是全球首款商用视频转音频 (V2A) 技术产品。这项突破性技术利用AI,仅凭视频数据即可自动生成高质量、与上下文相关的音频,包括声音设计、音效、拟音和环境音,为电影制作人、…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...