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

【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资源,但是如果粒度细的锁,被反复进行加锁解锁,可能实际效果还不如粒度粗的锁。

相关文章:

【JavaEE】常见锁策略、CAS

目录 常见的锁策略 乐观锁 vs 悲观锁 重量级锁 vs 轻量级锁 自锁锁和挂起等待锁 读写锁 可重入锁 vs 不可重入锁 公平锁 vs 非公平锁 CAS ABA问题 synchronized几个重要的机制 1、锁升级 2、锁消除 3、锁粗化 常见的锁策略 乐观锁 vs 悲观锁 乐观锁和悲观锁是锁的…...

Logstash 安装与部署(无坑版)

下载 版本对照关系:ElasticSearch 7.9.2 和 Logstash 7.9.2 ; 官方下载地址 选择ElasticSearch版本一致的Logstash版本 https://www.elastic.co/cn/downloads/logstash 下载链接:https://artifacts.elastic.co/downloads/logstash/logst…...

鸿蒙开发:ArkUI Toggle 组件

ArkUI提供了一套完整的UI开发工具集,帮助开发者高效完成页面的开发。它融合了语言、编译器、图形构建等关键的应用UI开发底座,为应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能以及实时界面预览工具等,可以支持…...

使用Matlab神经网络工具箱

综述 在大数据和人工智能时代,神经网络是一种最为常见的数据分析和拟合工具。本报告以常用分析软件Matlab为例,介绍其中神经网络工具箱使用方法。 Step 1: 打开matlab 安装matlab 2018以上版本后,双击图标打开。 Step 2: 打开神经网络拟合…...

【面试题】Hive 查询:如何查找用户连续三天登录的记录

1. 需求概述 在分析用户行为时,查询用户的连续登录数据是一个常见需求。例如,我们需要找出每个用户连续三天登录的记录。给定一个包含用户登录记录的表,我们需要对这些数据进行处理,提取出用户连续三天登录的日期。 2. 问题说明…...

高活跃社区 Doge 与零知识证明的强强联手,QED 重塑可扩展性

在 Web3 的广阔生态中,Doge 无疑是最具标志性和趣味性的项目之一。作为一种起源于网络文化的符号,Doge 从最初的互联网玩笑发展为如今备受全球关注的去中心化资产,依靠其独特的魅力和广泛的用户基础,构建了一个充满活力的社区。 …...

qt QAbstractTableModel详解

1、概述 QAbstractTableModel 是 Qt 框架中的一个类,用于在 Qt 应用程序中实现自定义的表格数据模型。它是 Qt 中的一个抽象基类,提供了创建和操作表格数据所需的接口。QAbstractTableModel 为模型提供了一个标准接口,这些模型将其数据表示为…...

掌握 Navicat 数据库结构设计 | 提升工作效率的秘诀

近期,我们介绍了 Navicat 17 的一系列的新特性,包括:兼容更多数据库、全新的模型设计、可视化 BI、智能数据分析、可视化查询解释、高质量数据字典、增强用户体验、扩展 MongoDB 功能、轻松固定查询结果、便捷 URI、支持更多平台等。今天&…...

Ollama AI 框架缺陷可能导致 DoS、模型盗窃和中毒

近日,东方联盟网络安全研究人员披露了 Ollama 人工智能 (AI) 框架中的六个安全漏洞,恶意行为者可能会利用这些漏洞执行各种操作,包括拒绝服务、模型中毒和模型盗窃。 知名网络安全专家、东方联盟创始人郭盛华表示:“总的来说&…...

vue 3:监听器

目录 1. 基本概念 2. 侦听数据源类型 1. 监听getter函数 2. 监听 ref 或 reactive 的引用 3. 多个来源组成的数组 4. 避免直接传递值!!! 3. 深层侦听器 4. 立即回调的侦听器 5. 一次性侦听器 6. watchEffect() 7. 暂停、恢复和停止…...

Java学习路线:Maven(四)Maven常用命令

在IDEA的Maven模块中,可以看到每个项目都有一个生命周期 这些生命周期实际上是Maven的一些插件,每个插件都有各自的功能,而双击这些插件就可以执行命令 这些命令的功能如下: clean:清除整个 target文件夹&#xff0c…...

服务器数据恢复—分区结构被破坏的reiserfs文件系统数据恢复案例

服务器数据恢复环境: 一台服务器中有一组由4块SAS硬盘组建的RAID5阵列,上层安装linux操作系统统。分区结构:boot分区LVM卷swap分区(按照顺序),LVM卷中划分了一个reiserfs文件系统作为根分区。 服务器故障…...

lua入门教程:type函数

在Lua中,type 函数是一个内置函数,用于返回给定值的类型。Lua 支持多种数据类型,包括 nil(空值)、boolean(布尔值)、number(数字)、string(字符串&#xff09…...

Java图片转word

该方法可以控制一页是否只显示存放一张图片 第一步 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency><dependency><groupId>org.apache…...

立体视觉的核心技术:视差计算与图像校正详解

立体视觉的核心技术&#xff1a;视差计算与图像校正详解 在立体视觉中&#xff0c;通过双目相机&#xff08;即左右两台相机&#xff09;的不同视角捕获的图像&#xff0c;结合几何关系&#xff0c;我们可以推算出场景中物体的深度。本文将深入讲解如何基于视差&#xff08;di…...

PaddleNLP的FAQ问答机器人

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【DDRNet模型创新实现人像分割】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实…...

2024年12月中国多场国际学术会议,EI检索录用!

2024年12月&#xff0c;多场国际学术会议将在中国多地召开&#xff0c;涵盖AI、机器人、大数据、网络安全、传感制造、环境工程、物联网等领域&#xff0c;促进学术交流&#xff0c;录用论文将EI检索&#xff0c;诚邀国内外专家参会。 第三届人工智能、人机交互和机器人国际学…...

日语学习的难易程度

日语学习的难易程度是一个相对主观的问题&#xff0c;它受到多种因素的影响&#xff0c;包括个人的语言学习能力、学习方法、学习时间、学习资源的可获得性以及个人对日语文化的兴趣和投入程度等。以下是对日语学习难易程度的一些分析&#xff1a; 优点与易学之处 文字系统&am…...

java-web-web后端知识小结

spring框架三大核心: IOC--控制反转 DI---依赖注入 AOP--面向切面编程 web开发技术小结 1.过滤器,JWT令牌 2.三层架构 IOC, DI AOP, 全局异常处理, 事务管理 mybatis 3.数据操作与存储 mysql 阿里云OSS(云存储) 各个技术的归属: 1.过滤器, cookie,session--javaWeb 2.JWT, 阿里…...

常见的排序算法(二)

归并排序 归并排序&#xff08;Merge Sort&#xff09;是一种基于分治法&#xff08;Divide and Conquer&#xff09;的排序算法。它将一个大的问题分解成小的问题&#xff0c;然后递归地解决这些小问题&#xff0c;最后合并&#xff08;merge&#xff09;得到最终的排序结果。…...

spark的RDD分区的设定规则

目录 一、第一种&#xff1a;parallelize 获取rdd时 二、第二种&#xff1a;通过外部读取数据-textFile 三、上面提到了默认分区数&#xff0c;那么默认分区是怎么计算呢&#xff1f; 一、第一种&#xff1a;parallelize 获取rdd时 没有指定&#xff1a;spark.default.paral…...

【点云网络】voxelnet 和 pointpillar

VoxelNet 和 pointpillar 这两个网络可以认为后者是前者的升级版本&#xff0c;都是采用了空间划分的方法&#xff0c; 一个是体素&#xff0c;一个是pillar, 前者是3D卷积处理中间特征&#xff0c;后者是2D卷积处理中间特征。 voxelnet voxelnet 应该是比较早的onestage的网…...

HAL库硬件IIC驱动气压传感器BMP180

环境 1、keilMDK 5.38 2、STM32CUBEMX 初始配置 默认即可。 程序 1、头文件 #ifndef __BMP_180_H #define __BMP_180_H#include "main.h"typedef struct {float fTemp; /*温度&#xff0c;摄氏度*/float fPressure; /*压力&#xff0c;pa*/float fAltitude; /*…...

探索Python音频处理的奥秘:Pydub库的魔法

文章目录 探索Python音频处理的奥秘&#xff1a;Pydub库的魔法第一部分&#xff1a;背景介绍第二部分&#xff1a;Pydub是什么&#xff1f;第三部分&#xff1a;如何安装Pydub&#xff1f;第四部分&#xff1a;Pydub的简单函数使用方法1. 打开音频文件2. 播放音频3. 导出音频文…...

LeetCode 热题100(七)【链表】(2)

目录 7.6合并两个有序链表&#xff08;简单&#xff09; 7.7两数相加&#xff08;中等&#xff09; 7.8删除链表的倒数第N个节点&#xff08;中等&#xff09; 7.9两两交换链表中的节点&#xff08;中等&#xff09; 7.10k个一组翻转链表&#xff08;困难&#xff09; 7.6…...

计算机网络 TCP/IP体系 网络层

一. 网络层的基本概念 网络层主要负责将数据从源端主机发送到目的端主机。在这一过程中&#xff0c;网络层要解决的关键问题是数据包的路由选择&#xff0c;即确定数据包通过互联网的最佳路径。 1.1 网络层的信息类型 数据包&#xff1a;这是网络层传输的主要形式&#xff0c…...

迈入国际舞台,AORO M8防爆手机获国际IECEx、欧盟ATEX防爆认证

近日&#xff0c;深圳市遨游通讯设备有限公司&#xff08;以下简称“遨游通讯”&#xff09;旗下5G防爆手机——AORO M8&#xff0c;通过了CSA集团的严格测试和评估&#xff0c;荣获国际IECEx及欧盟ATEX防爆认证证书。2024年11月5日&#xff0c;CSA集团和遨游通讯双方领导在遨游…...

实习作假:阿里健康实习做了RABC中台,还优化了短信发送流程

最近有二本同学说&#xff1a;“大拿老师&#xff0c;能帮忙看下简历吗&#xff1f;” 如果是从面试官的角度来看&#xff0c;这个同学的实习简历是很虚假的。 但是我们一直强调的是&#xff1a;校招的实习简历是不能出现明显的虚假。 首先&#xff0c;你去公司做事情&#…...

Unity中IK动画与布偶死亡动画切换的实现

在Unity游戏开发中&#xff0c;Inverse Kinematics&#xff08;IK&#xff09;是创建逼真角色动画的强大工具。同时&#xff0c;能够在适当的时候切换到布偶物理状态来实现死亡动画等效果&#xff0c;可以极大地增强游戏的视觉体验。本文将详细介绍如何在Unity中利用IK实现常规…...

java导出word文件(手绘)

文章目录 代码细节效果图参考资料 代码细节 使用的hutool的WordUtil&#xff0c;WordUtil对poi进行封装&#xff0c;但是这一块的官方封装的很少&#xff0c;很多细节都没有。代码中是常见的绘制段落&#xff0c;标题、表格等常用api Word07Writer writer WordUtil.getWriter(…...