【JavaEE】常见锁策略、CAS

目录

常见的锁策略

乐观锁 vs 悲观锁

重量级锁 vs 轻量级锁

自锁锁和挂起等待锁

读写锁

可重入锁 vs 不可重入锁

公平锁 vs 非公平锁

CAS

ABA问题

synchronized几个重要的机制

1、锁升级

2、锁消除

3、锁粗化


常见的锁策略

乐观锁 vs 悲观锁

乐观锁和悲观锁是锁的一种特性,不是一把具体的锁。

悲观和乐观,是对后续锁冲突是否频繁给出的预测:

  • 如果预测接下来锁冲突的概率不大,就可以少做一些工作,称为乐观锁
  • 如果预测接下来锁冲突的概率很大,就可以多做一些工作,称为悲观锁

重量级锁 vs 轻量级锁

轻量级锁,锁的开销比较小

重量级锁,锁的开销比较大

这两种锁和刚才的乐观悲观有关,乐观锁通常也就是轻量级锁,悲观锁通常也就是重量级锁。

自锁锁和挂起等待锁

        自旋锁,属于轻量级锁的一种典型实现,往往是纯用户态实现,比如使用一个while循环,不停的检查当前锁是否被释放,如果没释放,就继续循环,释放了就获取到锁,从而结束循环(忙等,虽然消耗了cpu,但是换来了更快的响应速度)。

        挂起等待锁,属于重量级锁的一种典型实现,要借助系统api来实现,一旦出现锁竞争了,就会在内核中触发一系列的动作(比如让这个线程进入阻塞状态,暂时不参与cpu调度)

读写锁

两个线程加锁过程中:

  • 读和读之间,不会产生竞争
  • 读和写之间,会产生竞争
  • 写和写之间,会产生竞争

把加锁分成两种:

  • 读加锁,读的时候,别的线程能读,但是不能写
  • 写加锁,写的时候,其他线程不能读也不能写

可重入锁 vs 不可重入锁

一个线程针对同一把锁,连续加锁2次,不会死锁,就是可重入锁,会死锁就是不可重入锁。

可重入锁会记录加锁线程信息,以便线程二次加锁,同时引入计数器,每加锁一次就+1,直到计数器为0才释放锁

公平锁 vs 非公平锁

当很多线程去尝试加一把锁的时候,一个线程能够拿到锁,其他线程阻塞等待,一旦第一个线程释放锁之后,接下来是哪个线程能够拿到锁呢?

公平锁:按照“先来后到”的顺序

非公平锁:剩下的线程以“均等”的概率,来重新竞争锁

操作系统提供的加锁api,默认情况就属于“非公平锁”,如果要想实现公平锁,还需要引入额外的队列,维护这些线程的加锁顺序

上述这些锁策略都是描述了一把锁的基本特点的,synchronized属于哪种锁呢?

  • 对于“悲观乐观”,自适应的
  • 对于“重量轻量”,自适应的
  • 对于“自旋 挂起等待”,自适应的
  • 不是读写锁
  • 是可重入锁
  • 是非公平锁

所谓自适应就是,初始情况下,synchronized会预测当前的锁冲突的概率不大,此时以乐观锁的模式来运行(此时也就是轻量级锁,基于自旋锁的方式来实现)

在实际使用过程中,如果发现锁冲突的情况比较多,synchronized就会升级成悲观锁(也就是重量级锁,基于挂起等待的方式来实现)

CAS

什么是CAS

CAS:全称Compare and swap,字面意思“比较并交换”,一个CAS涉及到以下操作:

假设内存中存在原数据V,旧的预期值A,需要修改的新值B

  1. 比较A与V是否相等
  2. 如果比较相等,将B写入V
  3. 返回操作是否成功

比较交换的也就是内存和寄存器 ,如下例子:

有一个内存 M,两个寄存器 A,B

CAS(V,A,B)

  • 如果M和A的值相同,把M和B的值进行交换,同时返回true
  • 如果M和A的值不同,无事发生,返回false

CAS其实就是一个cpu指令,一个cpu指令就能完成上述比较交换的逻辑,单个的cpu指令,是原子的,就可以使用CAS完成一些操作,进一步的替代“加锁”。

基于CAS实现线程安全的方式,也称为“无锁编程”

java中AtomicInteger和其他原子类,就是基于CAS的方式对int进行了封装 ,进行++就是原子的了。

public class Main {
    public static AtomicInteger count=new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
           //count++
            count.getAndIncrement();
           //++count
            count.incrementAndGet();
            //count--
            count.getAndDecrement();
            //--count
            count.decrementAndGet();
        });
        Thread t2=new Thread(()->{
            //count++
            count.getAndIncrement();
            //++count
            count.incrementAndGet();
            //count--
            count.getAndDecrement();
            //--count
            count.decrementAndGet();
        });
        t1.start();
        t2.start();
    }
}

前面的“线程不安全”本质上是进行自增的过程中,穿插执行了

CAS也是让这里的自增,不要穿插执行,核心思路和加锁是类似的

  • 加锁是通过阻塞的方式,避免穿插
  • CAS则是通过重试的方式,避免穿插 

基于CAS实现自旋锁

public class spinLock{
    private Thread owner=null;
    public void lock()
    {
        while(!CAS(this.owner,null,Thread.currentThread())) {

        }
    }
    public void unLock(){
        this.owner=null;
    }
}

ABA问题

        CAS进行操作的关键,是通过值“没有发生变化”来作为“没有其他线程穿插执行的判断依据”,但是这种判断方式不够严谨,更极端的情况下,可能有另一个线程穿插进来,把值从A->B->A,针对第一个线程来说,看起来好像是这个值没变,但是实际上已经被穿插执行了。

        要避免ABA问题,我们可以让判定的数值,按照一个方向增长即可,有增有减就可能出现ABA,只是增加,或者只是减少就不会出现ABA,但是一些情况下,本身就应该要能增能减,我们可以引入一个额外的变量,版本号,约定每次修改余额,都会让版本号自增,此时在使用CAS判定的时候,就不是直接判定余额了,而是判定版本号,看版本号是否是变化了,如果版本号不变,注定没有线程穿插执行了。

synchronized几个重要的机制

1、锁升级

JVM将synchronized锁分为无锁,偏向锁,轻量级锁,重量级锁状态,会依据情况,进行依次升级。

无锁->偏向锁->自旋锁(轻量级锁)->重量级锁

锁升级的过程是单向的,不能再降级了。

偏向锁:不是真的加锁,只是做了一个标记,核心思想就是“懒汉模式”的另一种体现,如果有别的线程竞争锁再升级成轻量级锁。

2、锁消除

锁消除是编译器优化的手段,编译器会自动针对你当前写的加锁代码,做出判定,如果编译器觉得这个场景不需要加锁,此时就会把你写的synchronized给优化掉。

比如StringBuilder不带synchronized,StringBuffer带有synchronized,如果在单个线程中使用StringBuffer,此时编译器就会自动的把synchronized给优化掉

3、锁粗化

锁的粒度,synchronized里头,代码越多,就认为锁的粒度越粗,代码越少锁的粒度越细。

粒度细的时候能够并发执行的逻辑更多,更有利于充分利用好多核CPU资源,但是如果粒度细的锁,被反复进行加锁解锁,可能实际效果还不如粒度粗的锁。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

从0开始linux(21)——文件(2)文件重定向

欢迎来到博主的专栏:从0开始linux 博主ID:代码小豪 文章目录 设备文件文件缓冲区重新认识文件描述符重定向 设备文件 在前一篇文章博主提到,当一个c/c进程运行时,会默认打开三个文件流,分别是stdin,stdout…

Claude 3.5 新功能 支持对 100 页的PDF 图像、图表和图形进行可视化分析

Claude 3.5 Sonnet发布PDF图像预览新功能,允许用户分析长度不超过100页的PDF中的视觉内容。 此功能使用户能够轻松上传文档并提取信息,特别适用于包含图表、图形和其他视觉元素的研究论文和技术文档。 视觉PDF分析:用户现在可以从包含各种视觉…

【SQL server】数据库远程连接配置

SQL server远程连接配置 1、数据库远程配置1.身份验证2. 建立入站规则3. SQLServer服务的启动 1、数据库远程配置 1.身份验证 所以在安装过程中需要注意涉及到的的身份验证中,要使用混合模式,并设置密码。2. 建立入站规则 在控制面板中的防火墙管理中…

【Vue 全家桶】5、Vuex(更新中)

目录 概念何时使用搭建vuex环境基本使用getter的使用四个map方法的使用vuex模块化命名空间 概念 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。使用 Vuex 可…

首推!AI大模型课程2024年最新版!从零基础到入行大模型算法工程师,看完这一篇就够了,学完来找我内推!

“ 技术学习无非涵盖三个方面,理论,实践和应用**”** 大模型技术爆火至今已经有两年的时间了,而且大模型技术的发展潜力也不言而喻。因此,很多人打算学习大模型,但又不知道该怎么入手,因此今天就来了解一下…

一站式搭建线上线下交友平台/全开源码交付前后端安装说明

功能亮点 灵魂匹配:基于个人喜好和兴趣,为你推荐最合适的交友对象。 真实认证:所有用户都经过严格认证,确保交友环境真实可靠。 隐私保护:强大的隐私设置,让你轻松掌控个人信息和交友动态。 互动便捷&…

基于数组实现的Huffman树和Huffman编码

一、Huffman树简介 1、定义 树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度。 在含有n 个带权叶子结点的二叉树中,其中带权路径长度(Weighted Path Length, WPL)最小的二叉树称为哈夫曼树, 也…

图说复变函数论重大错误:将无穷多各异平面误为同一面

黄小宁 医学若将前所未知的“新冠”病毒误为已熟知的流感病毒,后果...;数学将前所未知的点集误为已熟知的集就会引出一连串的重大错误。 h定理:点集AB的必要条件是A≌B。 证:(1)任何图≌自己是几何学最起码…

SDL简介和初次尝试

文章目录 SDL的用途和概念SDL下载 SDL的用途和概念 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台开发库 ,使用C语言写成,SDL提供了数种 操作 图像 ,声音输入输出的函数,让开发者使用 相识的代码 就能够开发出跨平台的…

WiFi一直获取不到IP地址是怎么回事?

在当今这个信息化时代,WiFi已成为我们日常生活中不可或缺的一部分。无论是家庭、办公室还是公共场所,WiFi都为我们提供了便捷的无线互联网接入。然而,有时我们可能会遇到WiFi连接后无法获取IP地址的问题,这不仅影响了我们的网络使…

【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程

1、定义图像显示函数 首先定义一个函数,函数的作用是通过plt库显示两幅图,为后续实验做准备。该函数的主要功能是: 从指定路径加载图像显示图像的基本信息将图像从BGR格式转换为RGB格式并在一个图形窗口中显示两幅图像进行对比 import nump…

Ftrans数据跨境传输方案:保护隐私与促进合作

数据跨境传输是指在不同国家、地区和法律框架下进行的数据交换和传输,数据跨境传输流程周期是数据产生--数据传输--数据接收,而困境来源也来自这3个环节: 1.本地合规限制 数据出口国(数据输出国)的法律对于数据收集的…

Mybatis学习笔记(三)

十、MyBatis的逆向工程 (一)逆向工程介绍 MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包…

Github 2024-11-08Java开源项目日报 Top9

根据Github Trendings的统计,今日(2024-11-08统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9Vue项目1经验丰富的Java(后端)开发人员核心面试问题和答案 | 互联网Java工程师进阶知识完全扫盲 创建周期:2085 天开发语言:Java协议…

【新闻文本分类识别】Python+CNN卷积神经网络算法+深度学习+人工智能+机器学习+文本处理

一、介绍 文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集(“体育类”, “财经类”, “房产类”, “家居类”, “教育类”, “科技类”, “时尚类”, “时政类”, “游戏类”, “娱乐类”),然…

数据结构 ——— 链式二叉树的前中后序遍历递归实现

目录 前言 链式二叉树示意图​编辑 手搓一个链式二叉树 链式二叉树的前序遍历 链式二叉树的中序遍历 链式二叉树的后序遍历 前言 在上一章学习了链式二叉树的前中后序遍历的解析 数据结构 ——— 链式二叉树的前中后序遍历解析-CSDN博客 接下来要学习的是代码实现链式…

<项目代码>YOLOv8 pcb板缺陷检测<目标检测>

YOLOv8是一种单阶段(one-stage)检测算法,它将目标检测问题转化为一个回归问题,能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法(如Faster R-CNN),YOLOv8具有更高的…

yarn报错`warning ..\..\package.json: No license field`:已解决

出现这个报错有两个原因 1、项目中没有配置许可证 在项目根目录package.json添加 {"name": "next-starter","version": "1.0.0",# 添加这一行"license": "MIT", }或者配置私有防止发布到外部仓库 {"priv…

大模型学习笔记------CLIP模型解读与思考

大模型学习笔记------CLIP模型详解 1、为什么提出CLIP模型2、CLIP模型详解3、CLIP模型的意义4、一些思考 上文说到,多模态大模型应该是非常有发展前景的,首先来学习 CLIP(Contrastive Language-Image Pretraining)这个多模态模型…

昇思25天学习打卡营第1天|快速入门

昇思25天学习打卡营第1天|快速入门 目录 昇思25天学习打卡营第1天|快速入门实操教程 一、MindSpore内容简介 主要特点: MindSpore的组成部分: 二、入门实操步骤 1. 安装必要的依赖包 2. 下载并处理数据集 3. 构建网络模型 4. 训练模型 5. 测试…