当前位置: 首页 > news >正文

【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的关键特性与功能

  1. ReentrantLock提供了公平锁的实现
  2. ReentrantLock提供了tryLock操作,该操作会立即返回,是否获取到锁,这对于避免死锁和实现超时机制非常有用。
  3. ReentrantLock搭配了Condition类完成等待通知,Condition比wait和notify更强点,Condition可以指定阻塞线程唤醒

4.3Semaphore类——信号量

信号量就是一个计数器,计系统资源的个数。
在底层中对信号量的两个基本操作分别为P操作和V操作
P操作——申请资源
V操作——释放资源
在java中JVM将这两个操作分别封装成acquire(申请资源),release(释放资源)

相关文章:

【JavaEE】多线程进阶

&#x1f921;&#x1f921;&#x1f921;个人主页&#x1f921;&#x1f921;&#x1f921; &#x1f921;&#x1f921;&#x1f921;JavaEE专栏&#x1f921;&#x1f921;&#x1f921; 文章目录 1.锁策略1.1悲观锁和乐观锁1.2重量级锁和轻量级锁1.3自旋锁和挂起等待锁1.4可…...

大模型LLM面试常见算法题-包括Attention和Transformer常见面试题

大模型&#xff1a; 位置编码有哪些&#xff1f; 介绍LoRA与QLoRA RAG和微调的区别是什么&#xff1f; 哪些因素会导致LLM的偏见&#xff1f; 什么是思维链&#xff08;CoT&#xff09;提示&#xff1f; Tokenizer的实现方法及原理 解释一下大模型的涌现能力&#xff1f;…...

90元搭建渗透/攻防利器盒子!【硬件篇】

前言 以下内容请自行思考后进行实践。 使用场景 在某些情况下开软件进行IP代理很麻烦&#xff0c;并不能实现真正全局&#xff0c;而且还老容易忘记&#xff0c;那么为了在实景工作中&#xff0c;防止蓝队猴子封IP&#xff0c;此文正现。 正文 先说一下实验效果&#xff1…...

用vue2+elementUI封装手机端选择器picker组件,支持单选、多选、远程搜索多选

单选注意点&#xff1a; touchmove.prevent: 在 touchmove 事件上添加 .prevent 修饰符&#xff0c;以阻止默认的滚动行为。 handleTouchStart: 记录触摸开始的 Y 坐标和当前的 translateY 值。 handleTouchMove: 计算触摸移动的距离&#xff0c;并更新 translateY 值。 han…...

『古籍自有答案』古风H5案例赏析

「古籍自有答案」&#xff0c;一部由新京报与字节跳动公益联合打造的古风H5&#xff0c;以诗意盎然的开篇引领用户穿梭于千年文脉。 part1. 创意定位 "人生有惑问先贤&#xff0c;先贤答案存古籍"&#xff0c;在这里&#xff0c;每一个灵魂的探问&#xff0c;都能在…...

Laravel模型事件完全指南:触发应用程序的动态行为

标题&#xff1a;Laravel模型事件完全指南&#xff1a;触发应用程序的动态行为 在Laravel框架中&#xff0c;模型事件提供了一种优雅的方式来处理Eloquent模型生命周期中的各种关键时刻。通过监听和响应这些事件&#xff0c;开发者可以自动化许多常见的任务&#xff0c;如日志…...

hot100 |八、二叉树

1-leetcode94. 二叉树的中序遍历 注意&#xff1a;√ 递归方法已经很熟练了&#xff0c;两种不同的递归方式迭代法需要注意&#xff0c;zrm就遇到了要求迭代实现&#xff0c;前序遍历和后续遍历其实不难&#xff0c;中序遍历用的少&#xff0c;注意看一看 // 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 中&#xff0c;通过清单文件&#xff08;AndroidManifest.xml&#xff09;配置的广播接收器&#xff08;BroadcastReceiver&#xff09;&#xff0c;系统会在特定的时机自动注册这些广播接收器。以下是详细的说明&#xff1a; 静态注册的广播接收器 静态注册的广播…...

嵌入式硬件电路常用设计软件

目录 1. Cadence Allegro 2. PADS 3. Altium Designer 4. Multisim 5. Protues 1. Cadence Allegro 功能&#xff1a; Cadence Allegro是Cadence公司推出的先进PCB&#xff08;Printed Circuit Board&#xff0c;印刷电路板&#xff09;设计布线工具&#xff0c;也是目前…...

c#的List<T>的SelectMany 和Select

在C#中&#xff0c;List<T>&#xff08;以及任何实现了IEnumerable<T>的集合&#xff09;的Select和SelectMany扩展方法都是LINQ&#xff08;Language Integrated Query&#xff09;的一部分&#xff0c;用于对集合中的元素进行查询和转换。 尽管它们的作用有些相…...

69.WEB渗透测试-信息收集- WAF、框架组件识别(9)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;68.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;8&#xff09; 有无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、字符串函数 测试用例如下&#xff1a; 1.1 CONCAT() 将多个字符串连接成一个字符串。 SELECT CONCAT(first_name, , last_name) AS full_name FROM users; -- 期望结果&#xff1a;John Doe, Jane Smith, Michael Johnson 1.2 SUBSTRING() 提取子字符串 SELECT SUBSTR…...

【c++刷题笔记-数组】day29:452. 用最少数量的箭引爆气球、 435. 无重叠区间 、 763.划分字母区间

452. 用最少数量的箭引爆气球 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;先按照左边界排序&#xff0c;当前的左边界大于前一个的右边界的时候&#xff0c;表示没有覆盖所以需要一根箭&#xff0c;反之则要更新为最小的右边界 重点&#xff1a;是区间覆盖问题…...

【数据结构】链表带环问题分析及顺序表链表对比分析

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

快速解决找不到krpt.dll,无法继续执行代码问题

对于那些遇到计算机开机出现由于无法找到krpt.dll&#xff0c;进而无法继续执行代码问题的用户。 krpt.dll是计算机系统中与DirectX紧密相关的重要文件&#xff0c;如果它出现问题&#xff0c;可能会对一些特定的软件或游戏的运行产生影响。实际上&#xff0c;我们有多种解决该…...

C# List、LinkedList、Dictionary性能对比

数据结构性能对比 List、LinkedList、Dictionary 1. ArrayList &#xff08;List&#xff1a;前传&#xff09; ArrayList 是一个特殊数组&#xff0c; 通过添加和删除元素就可以动态改变数组的长度。 ArrayList集合相对于数组的优点&#xff1a; 支持…...

【Spring Cloud】微服务的简单搭建

文章目录 &#x1f343;前言&#x1f384;开发环境安装&#x1f333;服务拆分的原则&#x1f6a9;单一职责原则&#x1f6a9;服务自治&#x1f6a9;单向依赖 &#x1f340;搭建案例介绍&#x1f334;数据准备&#x1f38b;工程搭建&#x1f6a9;构建父子工程&#x1f388;创建父…...

全球首款商用,AI为视频自动配音配乐产品上线

近日&#xff0c;海外推出了一款名为Resona V2A的产品&#xff0c;这是全球首款商用视频转音频 (V2A) 技术产品。这项突破性技术利用AI&#xff0c;仅凭视频数据即可自动生成高质量、与上下文相关的音频&#xff0c;包括声音设计、音效、拟音和环境音&#xff0c;为电影制作人、…...

Android系统栏透明模式终极指南:如何实现沉浸式UI设计

Android系统栏透明模式终极指南&#xff1a;如何实现沉浸式UI设计 【免费下载链接】SystemBarTint [DEPRECATED] Apply background tinting to the Android system UI when using KitKat translucent modes 项目地址: https://gitcode.com/gh_mirrors/sy/SystemBarTint …...

PostCSS-CSSNext终极指南:10个关键检查点确保CSS代码质量与兼容性

PostCSS-CSSNext终极指南&#xff1a;10个关键检查点确保CSS代码质量与兼容性 【免费下载链接】postcss-cssnext postcss-cssnext has been deprecated in favor of postcss-preset-env. 项目地址: https://gitcode.com/gh_mirrors/po/postcss-cssnext PostCSS-CSSNext是…...

socket.io-redis-adapter迁移指南:从socket.io-redis平滑升级到新版本

socket.io-redis-adapter迁移指南&#xff1a;从socket.io-redis平滑升级到新版本 【免费下载链接】socket.io-redis-adapter Adapter to enable broadcasting of events to multiple separate socket.io server nodes. 项目地址: https://gitcode.com/gh_mirrors/so/socket.…...

电力设施智能检测:TTPLA数据集赋能电网巡检自动化全流程指南

电力设施智能检测&#xff1a;TTPLA数据集赋能电网巡检自动化全流程指南 【免费下载链接】ttpla_dataset aerial images dataset on transmission towers and power lines 项目地址: https://gitcode.com/gh_mirrors/tt/ttpla_dataset 在电力行业数字化转型进程中&…...

多用途气动机器人结构设计(论文+DWG图纸+任务书+翻译+调研报告+实践小结)

多用途气动机器人结构设计聚焦于通过气动驱动系统实现机械结构的灵活操作&#xff0c;其核心作用在于整合气动元件与机械模块&#xff0c;构建具备多场景适应能力的执行平台。该设计以压缩空气为动力源&#xff0c;通过气缸、电磁阀及管路系统的协同控制&#xff0c;驱动末端执…...

程序员别再假装养生:你花3000块买保健品,却舍不得戒掉这3个坏习惯

深夜十一点&#xff0c;某程序员群突然炸了。有人发了张截图&#xff0c;是他双十一的购物记录&#xff1a;护肝片、维生素C、鱼油、钙片、褪黑素、护腰垫、人体工学鼠标......总价&#xff1a;6872元。底下评论清一色的"对自己好一点"、"程序员太难了"、&…...

基于QGIS分区统计与栅格重分类的GlobeLand30地表覆盖面积精准测算

1. 数据准备与预处理 做地表覆盖分析的第一步就是获取高质量的数据源。GlobeLand30作为国产30米分辨率全球地表覆盖数据&#xff0c;在精度和易用性上都有不错的表现。我去年参与的一个省级生态评估项目就用到了这套数据&#xff0c;实测下来分类效果相当可靠。 下载数据时有个…...

SI4463项目实战:如何像调试代码一样,用WDS3工具精准调试射频参数?

SI4463射频调试实战&#xff1a;用WDS3实现代码级精准配置 在嵌入式开发领域&#xff0c;我们早已习惯了通过断点调试、日志输出和变量监控来掌控程序行为。但当面对射频模块时&#xff0c;许多工程师却感到束手无策——那些神秘的十六进制配置值、模糊不清的寄存器描述&#x…...

终极开源数据标注工具:Label Studio完整使用指南

终极开源数据标注工具&#xff1a;Label Studio完整使用指南 【免费下载链接】label-studio Label Studio is a multi-type data labeling and annotation tool with standardized output format 项目地址: https://gitcode.com/GitHub_Trending/la/label-studio 在当今…...

手把手教你用PyTorch复现Qwen2.5的GQA:从MHA到GQA的代码演进与性能对比

从零实现Qwen2.5的GQA机制&#xff1a;PyTorch实战与性能深度剖析 当我们在讨论现代大语言模型的高效推理时&#xff0c;注意力机制的优化始终是核心议题。Qwen2.5采用的Grouped Query Attention(GQA)既不是对传统多头注意力(MHA)的简单改良&#xff0c;也不是多查询注意力(MQA…...