目录

  • 前言
  • 1.锁策略
    • 1.1 乐观锁和悲观锁
    • 1.2 重量级锁和轻量级锁
    • 1.3 挂起等待锁和自旋锁
    • 1.4 公平锁和非公平锁
    • 1.5 可重入锁和不可重入锁
    • 1.6 读写锁
  • 2.CAS
    • 2.1 CAS的应用
    • 2.2 CAS的ABA问题
  • 3.synchronized优化
    • 3.1锁升级
    • 3.2锁消除
    • 3.3锁粗化
  • 总结

前言

本篇文章主要介绍多线程中锁策略、CAS和synchronized优化,这三个都是多线程中比较重要的部分。

1.锁策略

在多线程编程中,锁是保证线程安全的重要手段。不同的锁策略适用于不同的场景,了解这些策略有助于我们编写高效、安全的并发程序。

1.1 乐观锁和悲观锁

在使用锁的时候,预测这个锁遇到冲突的概率
如果预测锁冲突概率比较高,就称为“悲观锁”,在悲观锁中,更倾向于阻塞操作,在访问数据前就进行加锁。
如果预测锁冲突概率比较低,就称为“乐观锁”,在乐观锁中,就会尝试其他方式代替阻塞(例如忙等)。

1.2 重量级锁和轻量级锁

重量级锁表示加锁的开销比较大,等待锁的线程,等待时间可能会比较长。
轻量级锁表示加锁的开销比较小,等待锁的线程会相对的比较短。

1.3 挂起等待锁和自旋锁

这里的两个锁是实现层面的。
挂起等待锁是悲观锁/重量级锁的典型实现,遇到锁冲突,就会让线程挂起等待(调度出CPU,等待被CPU唤醒)
自旋锁则是乐观锁/轻量级锁的典型实现,遇到锁冲突,不会放弃CPU,而是通过忙等的方式,再次尝试获取锁。

1.4 公平锁和非公平锁

公平锁遵循“先来后到”,按照线程尝试抓取锁的顺序来进行获取。
非公平锁不遵循“先来后到”,而是“概率均等”,每一个尝试抓取锁的线程在线程解锁后都有可能抓取到。

1.5 可重入锁和不可重入锁

一个线程针对一个锁连续加锁两次,不触发死锁,则是可重入锁,反之则是不可重入锁。

1.6 读写锁

读写锁会把加锁操作分成两种:读锁和写锁,在很多场景下,数据读的次数比写的次数要频繁很多,所以把读写锁分开,在读锁和读锁之间不会产生互斥,读锁和写锁,写锁和写锁之间才会产生互斥。这样降低了很多锁冲突带来的性能损失。

2.CAS

CAS全称compare and swap(比较和交换)
我们假设内存中原数据是V,旧的预期值是A,需要修改的新值是B,我们首先比较V和A是否相等,如果相等,将B写入V,然后返回一个布尔值。
这里比较特殊的是,这个逻辑是通过一个CPU指令来完成的,
A和B是存储在两个寄存器当中,假设寄存器分别为寄存器1,寄存器2,将原数据与寄存器1的值比较,如果相等,就把原数据的值赋值给寄存器2。也就是说,这个操作是原子的,意味着线程安全,不需要加锁。

2.1 CAS的应用

  1. cas实现原子类
    在标准库中java.util.concurrent.atomic包里面的类都是基于这种方式来实现的,下面是这个包中的各种类:
    在这里插入图片描述
    这里典型的一个类就是AtomicInteger,其中getAndIncrement就相当于i++操作,下面看一个例子:
    private static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {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);}

这里使用了AtomicInteger类来实现多线程实现同时自增一个变量,可以看到不进行加锁的情况下,结果也正确:
在这里插入图片描述

  1. CAS实现自旋锁
    使用CAS可以实现自旋锁,下面看伪代码:
public class SpinLock {private Thread owner = null;public void lock(){// 通过 CAS 看当前锁是否被某个线程持有.// 如果这个锁已经被别的线程持有, 那么就⾃旋等待.// 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程.while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}
}

循环里判断锁是否被占用,如果被占用,就会一直循环,直到不被占用,解锁状态。

2.2 CAS的ABA问题

假设有两个线程T1和T2:
线程T1读取共享变量的值为A。
然后线程T2将共享变量的值从A修改为B,再修改回A。
最后线程T1再次读取共享变量的值为A,由于值与最初读取的A相同,因此CAS操作成功,但实际上共享变量的状态已经被T2修改过。
这样T1就无法区分这个变量是否经历了一系列修改还是始终是A
解决方案:
可以给要修改的值引入版本号,比较当前值和旧值时,也要比较版本号是否符合预期:如果当前版本号和读到的版本号相同, 则修改数据, 并把版本号 + 1;如果当前版本号⾼于读到的版本号. 就操作失败(认为数据已经被修改过了)。

3.synchronized优化

3.1锁升级

synchronized具有自适应的特性,会根据情况进行锁升级,JVM将synchronized分为无锁、偏向锁、轻量级锁、重量级锁状态,会依次进行升级。
轻量级锁和重量级锁前面已经简要介绍,这里介绍一下偏向锁。
偏向锁并没有给线程真正加锁,只是记录这个锁属于哪个线程,如果没有线程进行竞争这个锁,偏向锁状态就保持,直到最终解锁;如果遇到其他线程来竞争这个锁,就在其他线程获取锁之前,抢先获取到这个锁,也可以让其他线程阻塞,保证线程安全。

3.2锁消除

有些代码中写了加锁,但是如果JVM执行时发现不需要加锁,就会自动把锁去掉。比如StringBuffer带有synchronized锁,如果在单线程情况下使用,JVM和编译器则会进行判断,将锁”消除“。

3.3锁粗化

这里涉及的是锁的粒度
加锁和范围中代码越多,锁的粒度越粗。
如果有一系列独立的加锁、解锁操作,JVM可以回将他们合并成一个更大的锁范围,只加锁解锁一次,这样减少了系统的调用开销,同时也减少了锁竞争。

总结

本篇文章介绍了锁策略,CAS以及synchronized的优化,在后面会对synchronized进行总结。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90789.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90789.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/90789.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows符号链接解决vscode和pycharm占用C盘空间太大的问题

Windows符号链接解决vscode和pycharm占用C盘空间太大的问题 参考文章&#xff1a;Windows符号链接 1、找到vscode和pycharm在C盘的缓存文件夹。 C:\Users\用户名\AppData\Roaming\Code C:\Users\用户名\.vscode\extensionsC:\Users\用户名\AppData\Local\JetBrains C:\Users…

赋能家庭、行业与工业场景,智微智能新一代Twin Lake 全栈智能终端发布

在数字化浪潮席卷全球的今天&#xff0c;智能终端已成为连接物理世界与数字世界的核心枢纽。智微智能基于Intel Twin Lake平台&#xff0c;推出覆盖家庭/行业应用及工业物联网的全场景产品矩阵&#xff0c;为不同场景下的用户提供高效、可靠的产品和解决方案。Intel Twin Lake架…

复习笔记 31

前言 好好复习。今天距离考研初试还剩一百六十一天。我的时间其实没剩多少了呀。我得好好加油。 归并排序 #include<algorithm> #include<iostream>using namespace std;const int N 100010; int n; int a[N], tmp[N];void merge ( int a[], int l, int r ) {if (…

el-tree 懒加载 loadNode

el-tree 是 Element UI 提供的树形组件&#xff0c;其懒加载功能通过 loadNode 方法实现&#xff0c;可以在用户展开节点时动态加载子节点数据&#xff0c;避免一次性加载大量数据。下面介绍 loadNode 的具体用法和示例。基本用法loadNode 是 el-tree 的一个重要属性&#xff0…

【机器学习入门巨详细】(研0版)二创OPEN MLSYS

自学机器学习&#xff0c;从入门到精通导论机器学习的基本框架设计目标机器学习框架基本组成原理机器学习生态机器学习工作流环境配置数据处理模型定义损失函数和优化器训练及保存模型测试及验证模型定义深度神经网络以层为核心定义神经网络神经网络层实现原理自定义神经网络层…

Excel 转 JSON by WTSolutions API 文档

Excel 转 JSON by WTSolutions API 文档 简介 Excel 转 JSON API 提供了一种简单的方式将 Excel 和 CSV 数据转换为 JSON 格式。该 API 接受制表符分隔或逗号分隔的文本数据&#xff0c;并返回结构化的 JSON。 接口端点 POST https://mcp.wtsolutions.cn/excel-to-json-api 请求…

git版本发布

cvs和svn都是集中式版本控制系统,而git是分布式版本控制系统。 1、集中式版本控制系统必须联网才能工作&#xff0c;如果在局域网内还好&#xff0c;带宽够大&#xff0c;速度够快&#xff0c;可如果在互联网上&#xff0c;遇到网速慢的话&#xff0c;呵呵。分布式版本控制系统…

138-EMD-KPCA-CPO-CNN-BiGRU-Attention模型!

138-EMD-KPCA-CPO-CNN-BiGRU-Attention基于经验模态分解和核主成分分析的长短期记忆网络改进多维时间序列预测MATLAB代码&#xff01;其中&#xff08;含CPO-CNN-BiGRU-attention、EMD-CPO-CNN-BiGRU-Attention、EMD-KPCA-CPO-CNN-BiGRU-Attention三个模型的对比&#xff09; 可…

系统思考:多元胜过能力

系统思考&#xff1a;从整体出发&#xff0c;打破瓶颈&#xff0c;拥抱多元 我们是否曾经陷入过这样的困境&#xff1f; 1、专注能力提升&#xff0c;却无法突破瓶颈&#xff1a;我和团队日复一日地努力提升个人能力&#xff0c;投入无数时间和精力&#xff0c;但始终无法打破现…

qt样式整合持续更新中(实测有效的)

// 仅显示上边框 一般可以作为直线使用 border-top: 2px solid black; //画虚线 border-bottom: 2px dashed white; //单个圆角 border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; //透明背景 background:rgba(0,0,0,0); //设置字体 font:15pt; //给button设置…

[java][springboot]@PostConstruct的介绍和用法

在 Spring Boot&#xff08;以及整个 Spring Framework&#xff09;中&#xff0c;PostConstruct 是一个非常常用的注解&#xff0c;用于在 依赖注入完成后 执行一些初始化操作。import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Component;Co…

Leaflet面试题及答案(41-60)

查看本专栏目录 文章目录 🟢 面试问题及答案(41-60)41. 如何判断某个点是否在地图可视区域内?42. 如何动态更新 Marker 位置?43. 如何清除地图上的所有图层?44. 如何保存地图截图?45. 如何检测浏览器是否支持触摸?46. Leaflet 是否支持 TypeScript?47. 如何修改默认图…

Redis事件机制

Redis 采用事件驱动机制来处理大量的网络IO。它并没有使用 libevent 或者 libev 这样的成熟开源方案&#xff0c;而是自己实现一个非常简洁的事件驱动库 ae_event。事件机制Redis中的事件驱动库只关注网络IO&#xff0c;以及定时器。该事件库处理下面两类事件&#xff1a;文件事…

Linux基础开发工具

目录 1.写在前面 2.权限 3.file命令 4.基础开发工具 1.软件包管理器 5.编辑器vim 1.写在前面 我们在上一讲解中讲解了权限是人事物属性&#xff0c;还知道了拥有者所属组其他人这三个概念&#xff0c;知道了33一组&#xff0c;rwx分别代表什么。那么下面我们继续进行权限…

ICCV2025 特征点检测 图像匹配 RIPE

目测对刚性物体效果比较好代码&#xff1a;https://github.com/fraunhoferhhi/RIPE 论文&#xff1a;https://arxiv.org/abs/2507.04839import cv2 import kornia.feature as KF import kornia.geometry as KG import matplotlib.pyplot as plt import numpy as np import torc…

Ubuntu22.0.4安装PaddleNLP

Ubuntu22.0.4安装PaddleNLP环境说明安装底层框架Paddle安装PddleNLP1. pip安装2. 验证安装3. 最后问题集锦环境说明 1. miniconda 25.5.1 2. python 3.12.11 3. pip 25.1 4. nvidia 570.144 5. cuda 12.8**注意&#xff1a;**安装过程可能遇到的一些问题&#xff0c;参考末尾的…

【HTTP服务端】Cookie?Session?Token?

文章目录cookie与sessiontoken什么是JWT&#xff1f;JWT的组成结构1. Header&#xff08;头部&#xff09;2. Payload&#xff08;负载&#xff09;3. Signature&#xff08;签名&#xff09;JWT工作原理JWT的特点安全注意事项cookie与session cookie有哪些属性 键值对&#xf…

安装Git

Git安装避坑指南技术 操作系统选择与准备 Windows用户需注意系统版本兼容性&#xff0c;建议使用Windows 10及以上版本 Mac用户需检查是否安装Xcode Command Line Tools Linux用户需区分apt/yum等包管理器命令差异 安装包下载注意事项 从官方渠道&#xff08;git-scm.com&a…

UDP服务器的优缺点都包含哪些?

UDP协议不需要像TCP协议那样进行复杂的连接建立与拆除过程&#xff0c;在进行传输数据信息的过程中&#xff0c;应用层将数据交给UDP层&#xff0c;UDP层直接加上首部就发往网络层&#xff0c;极大地减少了处理时间和资源消耗。例如在一些简单的网络监控程序中&#xff0c;只是…

sqli-labs靶场通关笔记:第7-8关 布尔盲注

第七关1.审题这里判断出是))闭合&#xff0c;但是页面只有正确和错误的回显状态&#xff0c;报错的回显也是固定的&#xff0c;没有显示报错具体信息。这关使用的方法是布尔盲注。为什么叫布尔盲注&#xff1f;因为它返回的结果只有true和false 两个值&#xff0c;攻击者需要通…