CAS 和 synchronized 的优化过程

news2024/9/21 16:08:16

🍉 目录

CAS 的实现

CAS 的工作原理

优化过程

CAS 的应用

1) 实现原子类

2)实现自旋锁 

CAS 的 ABA 问题

synchronized 的 原理

synchronized 基本特点

加锁工作过程

其他优化操作 

1. 锁消除

2. 锁粗化 


CAS(Compare-And-Swap,即 比较和交换),是用于实现同步原语的一种原子操作。在Java的并发编程中,CAS 操作是轻量级和无锁算法的基础,它允许线程在不使用传统互斥锁的情况下安全地更新共享变量。以下是 CAS 优化的详细解释。

CAS 操作的引入主要是为了在多线程环境下提供一种高效、低开销的同步机制。通过避免使用重量级锁,CAS 操作可以减少线程的上下文切换和锁竞争带来的性能损失。

CAS 的实现

针对不同的操作系统,JVM 用到了不同的 CAS 实现原理,简单来讲:

1. Java的 CAS 利用的是 unsafe 这个类的提供的 CAS 操作

2. unsafe 的 CAS 依赖的是 JVM 针对不同的操作系统实现的 Atomic::cmpxchg

3. Atomic::cmpxchg 的实现使用了汇编的 CAS 操作,并使用 CPU 硬件提供的 lock 机制保证其原子性。

简而言之,当硬件层面予以支持,软件层面才得以实现。

CAS 的工作原理

CAS 操作的基本思想是比较并交换。它包含三个参数:内存位置(V)、预期值(A)和新值(B)。CAS 操作会检查内存位置 V 的值,与预期值 A 是否相等,如果相等则将 V 替换为 B,否则不进行任何操作。CAS 操作是原子的,即它在硬件层面上是不可分割的,这确保了操作的线程安全性。

优化过程

🍉减少锁的使用

在许多情况下,CAS 操作可以替代传统的锁机制,从而避免锁带来的开销和竞争。通过使用 CAS 操作,线程可以在不阻塞的情况下尝试更新共享变量,这提高了系统的并发性能。

🍉自旋等待

当 CAS 操作失败时(即内存值与预期值不符时),即没有拿到锁对象时,线程也不会立即进入阻塞状态而是会开始自旋等待状态。在自旋等待期间线程会不断的重新尝试 CAS 操作,直到成功或者到某个自旋时间的阀阈值。这种自旋等待机制减少了线程上下文切换的开销,并提高了系统的相应速度。

🍉减少内存开销

CAS 操作通常只需要对少量的内存位置进行操作,这减少了内存带宽的消耗。相比之下,传统的锁机制需要维护一个复杂的等待队列和锁状态,这会增加内存开销。

🍉提高可扩展性

CAS操作是基于硬件原语的,因此它可以很好地扩展到多核处理器环境。在多核处理器上,CAS操作可以并行执行,而传统的锁机制可能需要跨核进行复杂的同步操作。

🍉避免死锁

由于CAS操作不涉及锁的持有和释放,因此它避免了死锁问题的发生。死锁是传统锁机制中常见的问题之一,它会导致线程永久性地阻塞在等待锁的状态下。

CAS 的应用

1) 实现原子类

Java 标准库库中提供了 java.util.concurrent.atomic 包,里面的类都是基于这种方式来实现的。典型的就是 AtomicInteger 类,其中的 getAndIncrement 相当于 i++ 操作。

AtomicInteger atomicInteger = new AtomicInteger ( 0 );
// 相当于 i++
atomicInteger.getAndIncrement();

 原子类伪代码

class AtomicInteger {
   private int value;
   public int getAndIncrement () {
      int oldValue = value;
      while ( CAS(value, oldValue, oldValue+ 1 ) != true ) {
              oldValue = value;
       }
            return oldValue;
    }
}

CAS 操作修改同一个变量是,直接读取内存而不是寄存器,修改也是直接修改的内存。是一条硬件指令,是原子的。

代码实现

public class Demo22 {
    public 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 = "+count);

    }
}

结果显示

通过形如上述代码就可以实现一个原子类,不需要使用重量级锁,就可以高效完成自增操作。

2)实现自旋锁 

基于 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 ;
          }
}

CAS 的 ABA 问题

 ABA 问题 :

假设存在两个线程 t1 和 t2 。如果有一个共享变量 num,初始值为A。

线程 t1 需要将原始 A 的值修改为 B(如果被其他线程修改了也没关系,一共修改为 B 只需要修改一次) ,在 t1 刚刚读取到 A 的值(value = A,oldvalue = A ),这时穿插了线程 t2 的执行,线程 t2 将 A 修改为 B 后,又将 B 修改为 A(value = A)。现在值被修改为 B 执行了一次,但是 t1 现在进行判断时,发现 value = oldvalue ,那么此时意味着 t1 也会修改 A 变为 B ,但是此时的修改是第二次,此时是第二次操作修改是错误的。(具体执行如下)

针对上面的 ABA 问题的解决方案

为了解决这个问题,可以使用版本号或时间戳来跟踪内存位置的变化。

针对上述修改值这个问题,我们引入一个版本号,每次判断 value 和 oldvalue 的时候也需要判断版本号,查看版本号是否和每次操作时读取的版本号一致。 在上面的 ABA 问题中引入版本号,当线程 t1 第一次读取的时候,版本号为1,后来经过 t2 的两次修改,虽然 num 的值变为了 A ,但是版本号不等于1,说明在 t1 未执行这段期间 t2 已经执行了(假设执行的就是 A 转变为了 B)。

如下图

synchronized 的 原理

synchronized 基本特点

1)开始为乐观锁,如果锁冲突频繁,转变为悲观锁

2)开始是轻量级锁实现,如果锁被持有的时间较长,转变为重要量级锁

3)实现轻量级锁的时候大概率需要用到自旋锁策略

4)synchronized 是一种可重入锁

5)synchronized 是一种不公平锁

6)synchronized 不是读写锁

加锁工作过程

🍉 偏向锁状态

工作原理:当只有一个线程(偏向线程)访问同步代码块或方法时,JVM会在对象的对象头中设置一个偏向锁标志,并将线程ID记录在对象头中。后续该线程再次访问时,只需检查对象头中的线程ID是否与其自身ID一致,若一致则无需进行任何同步操作,直接进入同步代码块。

 撤销与升级: 当有其他线程(竞争线程)尝试获取锁时,JVM会检测到偏向锁状态,并尝试撤销偏向锁,将锁升级为轻量级锁。

🍉 轻量级锁状态(轻量级锁是为了在线程交替执行同步块时提高性能而设计的)

随着其他线程进⼊竞争, 偏向锁状态被消除, 进⼊轻量级锁状态(⾃适应的⾃旋锁).
此处的轻量级锁就是通过 CAS 来实现.
通过 CAS 检查并更新⼀块内存 (⽐如 null => 该线程引⽤)
如果更新成功, 则认为加锁成功
如果更新失败, 则认为锁被占⽤, 继续⾃旋式的等待(并不放弃 CPU)
⾃旋操作是⼀直让 CPU 空转, ⽐较浪费 CPU 资源.
因此此处的⾃旋不会⼀直持续进⾏, ⽽是达到⼀定的时间/重试次数, 就不再⾃旋了.
也就是所谓的 "⾃适应"

     🚩自旋等待:自旋等待期间,线程会在一个小的循环中重复尝试获取锁,直到锁被释放或自旋次数超过阈值。

🍉 重量级锁状态(当锁竞争非常激烈,轻量级锁的自旋尝试无法快速获取锁时,JVM会将锁膨胀为重量级锁)

重量级锁使用操作系统提供的互斥量(mutex)机制来确保线程间的同步。线程会进入阻塞状态,并被放入等待队列(如Contention List Queue)中等待锁被释放。

      🚩锁释放与唤醒:当持有锁的线程执行完同步代码块并释放锁时,JVM会随机唤醒等待队列中的一个线程。

如下图:

其他优化操作 

JVM 根据配置和实现对 synchronized 锁的优化操作还有 锁消除、锁粗化。

1. 锁消除
编译器+ JVM  判断锁是否可消除,如果可以,就直接消除。什么意思呢???(一脸问号)
举个栗子:
StringBuffer sb = new StringBuffer ();
sb.append( "a" );
sb.append( "b" );
sb.append( "c" );
sb.append( "d" );
此时每个 append 的调⽤都会涉及加锁和解锁. 但如果只是在单线程中执⾏这个代码, 那么这些加锁解锁操作是没有必要的, ⽩⽩浪费了⼀些资源开销。
2. 锁粗化 
⼀段逻辑中如果出现多次加锁解锁, 编译器 + JVM 会⾃动进⾏锁的粗化。
锁的粒度:粗和细
实际开发过程中, 使⽤细粒度锁, 是期望释放锁的时候其他线程能使⽤锁.
但是实际上可能并没有其他线程来抢占这个锁. 这种情况 JVM 就会⾃动把锁粗化, 避免频繁申请释放锁。

🚩文化篇:真光之人,压抑愈久,深潜愈甚,其光华之绽放乃愈灿烂也。 

以上就是本期的全部内容啦~希望对大家有帮助~~

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

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

相关文章

反编译 AndroidManifest.xml文件-android反编译技术

一、安卓打包后目录 想要查看原来版本配置和关联信息&#xff0c;被打包了&#xff0c;这时候需要工具 AXMLPrinter2.jar 二、反编译环境要求 序号软件说明1java电脑得有java环境2AXMLPrinter2.jarapk中xml解析文件 三、反编译指令 java -jar AXMLPrinter2.jar "C:\Us…

腾讯百度阿里华为常见算法面试题TOP100(4):双指针、哈希、滑动窗口

之前总结过字节跳动TOP50算法面试题&#xff1a; 字节跳动常见算法面试题top50整理_沉迷单车的追风少年-CSDN博客_字节算法面试题 目录 双指针 42.接雨水 283.移动零 11.盛最多水的容器 15.三数之和 哈希 1. 两数之和 49.字母异位词分组 128.最长连续序列 滑动窗…

2024 RSTCONCTF re 部分wp

Unknown Architect DIE查看&#xff0c;RISC_V架构&#xff0c;直接交即可 Duke of the Kingdom 附件拖入jadx 比较简单。脚本 Keypad 附件拖入ida。一共四遍check&#xff0c;都比较简单 Pico-Cypher 文本编辑器打开附件 稍微问一问gpt&#xff0c;得知这是micropython&#x…

数据驱动型营销与开源 AI 智能名片 O2O 商城系统的融合发展

摘要&#xff1a;本文探讨了数据驱动型营销在现代商业中的重要性&#xff0c;阐述了其在消费者管理和产品管理方面的作用。同时&#xff0c;引入“开源 AI 智能名片 O2O 商城系统”&#xff0c;分析其如何与数据驱动型营销相结合&#xff0c;为企业提供更精准的营销决策和更高效…

【Matlab 肌电信号分析】

一、数据预处理 1.1 数据读取 使用matlab从rhd文件中读取原始数据&#xff0c;共64个通道。 1.2 数据滤波 使用 60Hz的Notch filter 和150Hz的高通Butterworth滤波器进行降噪 二、波峰提取 > 每个通道分别根据相应的规则提取出波峰、波谷附近的波形。 三、信号聚类 3.1 降…

win7桌面显示我的电脑,控制面板等

win7桌面显示我的电脑&#xff0c;控制面板等 点击windows图标&#xff0c;一般左下角 右键计算机 选择在桌面显示即可&#xff0c;控制面板也是一样的操作

可自动完成固化、繁琐、重复的工作流程,提高工作效率的智慧快消开源了

智慧快消视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。国产化人工智能“…

1.4 计算机网络的性能指标

欢迎大家订阅【计算机网络】学习专栏&#xff0c;开启你的计算机网络学习之旅&#xff01; 文章目录 前言一、速率二、带宽三、吞吐量四、时延五、时延带宽积六、往返时延&#xff08;RTT&#xff09;七、利用率 前言 计算机网络的性能指标是评估网络效率和效果的关键&#xf…

React学习day07-ReactRouter-抽象路由模块、路由导航、路由导航传参、嵌套路由、默认二级路由的设置、两种路由模式

14、ReactRouter续 &#xff08;2&#xff09;抽象路由模块 1&#xff09;新建page文件夹&#xff0c;存放组件 组件内容&#xff1a; 2&#xff09;新建router文件夹&#xff0c;在其下创建实例 3&#xff09;实例导入&#xff0c;使用 4&#xff09;效果 &#xff08;3&…

CAD图纸加密软件哪个好?10款2024主流CAD图纸加密软件分享!

随着信息安全意识的增强&#xff0c;特别是在工程设计、建筑和制造等领域&#xff0c;保护CAD图纸的安全成为一项重要任务。选择合适的CAD图纸加密软件不仅能确保数据安全&#xff0c;还能提高企业的合规性。以下是2024年主流的10款CAD图纸加密软件&#xff0c;每款软件均有独特…

floodfill算法(二)

目录 一、太平洋大西洋水流问题 1. 题目链接&#xff1a;417. 太平洋大西洋水流问题 2. 题目描述&#xff1a; 3. 解法 &#x1f334;算法思路&#xff1a; &#x1f334;算法代码&#xff1a; 二、扫雷游戏 1. 题目链接&#xff1a;529. 扫雷游戏 2. 题目描述&#xf…

Java8的Optional简介

文章目录 环境背景方法1&#xff1a;直接获取方法2&#xff1a;防御式检查方法3&#xff1a;Java 8的Optional概述map()测试 flatMap()测试 总结参考 注&#xff1a;本文主要参考了《Java 8实战》这本书。 环境 Ubuntu 22.04jdk-17.0.3.1 &#xff08;兼容Java 8&#xff09; …

samba配置

首先需要在linux上使用命令sudo apt install samba安装samba功能&#xff0c;安装之后&#xff0c;使用命令sudo smbpasswd -a zxy添加samba的密码&#xff0c;我这里使用的是和ubuntu的登陆密码&#xff0c;然后需要编辑samba相关的功能&#xff0c;使用命令sudo vim /etc/sam…

通信工程学习:什么是AN-SMF接入网系统管理功能

AN-SMF接入网系统管理功能 AN-SMF&#xff08;Access Network System Management Function&#xff0c;即接入网系统管理功能&#xff09;是通信网络中接入网&#xff08;AN&#xff09;的一个重要组成部分&#xff0c;主要负责协调和管理接入网内的各种功能和资源。以下是对AN…

【Android Studio】app:compileDebugJavaWithJavac FAILED解决办法

文章目录 问题描述解决办法 问题描述 Task :app:compileDebugJavaWithJavac FAILED The following annotation processors are not incremental: jetified-butterknife-compiler-10.0.0.jar (com.jakewharton:butterknife-compiler:10.0.0). Make sure all annotation processo…

启动windows更新/停止windows更新,电脑自动更新怎么彻底关闭?如何操作?

关于启动Windows更新、停止Windows更新以及彻底关闭电脑自动更新的问题&#xff0c;以下是根据专业角度提供的详细指导&#xff1a; 启动Windows更新 1.通过Windows设置启动更新&#xff1a; -点击开始菜单&#xff0c;选择“设置”&#xff08;或使用快捷键WinI&a…

主流的Java的webapi接口模板特点分析

Java 作为一种广泛应用于企业级开发的编程语言&#xff0c;其在 Web API 开发中具有重要的地位。随着 Java 生态系统的不断发展&#xff0c;市面上涌现了多种不同的 Web API 框架和设计模式。不同的 Web API 模板在设计上各有特点&#xff0c;适合不同类型的开发需求。本文将详…

明月皎皎,思念悠悠 孙滢迎深情演唱《月亮与笆篓》

明月皎皎&#xff0c;思念悠悠 孙滢迎深情演唱《月亮与笆篓》 在中秋佳节的月光下&#xff0c;一首满含对妈妈思念的歌曲《月亮与笆篓》&#xff0c;如同一缕轻柔的晚风&#xff0c;悄然拂过心间&#xff0c;勾起无尽的回忆与眷恋。 该歌曲由全国机关事务管理研究会。徐进作词…

2022高教社杯全国大学生数学建模竞赛C题 问题一(3) Python代码

目录 1.3 根据风化点检测数据,预测其风化前的化学成分含量数据重塑数据可视化回归随机森林回归XGboost回归Gradient Boosting回归LightGBM回归CatBoost回归决策树回归MLP回归预测数据复原1.3 根据风化点检测数据,预测其风化前的化学成分含量 数据重塑 import numpy as npdf=…

『功能项目』第二职业法师的平A【57】

我们打开上一篇56制作提示主角升级面板的项目&#xff0c; 本章要做的事情是制作法师平A的魔法球触碰到Boss后让Boss受到一个无视攻击力与防御力的一个&#xff08;100&#xff09;左右随机的一个伤害值 修改脚本&#xff1a;PlayerCtrl.cs 将法师职业生成的魔法球的标签Tag设…