CAS概述

news2024/11/16 17:29:22

目录

    • 一、CAS与原子类
      • 1.1 CAS
      • 1.2 乐观锁与悲观锁
      • 1.3 原子操作类
    • 二、 synchronized优化
      • 2.1 轻量级锁
      • 2.2 轻量级锁-无竞争
      • 2.3 轻量级锁-锁膨胀
      • 2.4 重量级锁-自旋
      • 2.5 偏向锁
      • 2.6 synchronized-其他优化

一、CAS与原子类

1.1 CAS

CAS(一种不断尝试)即Compare and Swap,它体现的一种乐观锁的思想,比如多个线程要对一个共享的整形变量执行+1操作:
在这里插入图片描述
CompareAndSwap:尝试把结果赋值给前面的共享变量,赋值的同时将旧值与共享变量当前的值作比较【怕写入结果时有其他线程已经将共享变量的值修改】

获取共享变量时,为了保证该变量的可见性,需要使用volatile修饰。结合CAS和volatile可以实现无锁并发,使用于竞争不激烈、多核CPU的场景下。

● 因为没有使用synchronized,所以线程不会陷入阻塞(CAS需要不断重试进而利用CPU时间),这是效率提升的因素之一
● 但如果因为竞争激烈,可以想到重连必然频繁发生,反而效率会受影响

CAS底层依赖于一个Unsafe类来直接调用操作系统底层的CAS指令,下面是直接使用Unsafe对象进行线程安全保护的例子

1.2 乐观锁与悲观锁

● CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算修改了也没关系,花费点时间再重试而已

● synchronized是基于悲观锁的思想:最悲观的估计,时刻得防着其他线程来修改共享变量,只要线程上了锁就别想修改,完全解开了锁其他线程才有机会

1.3 原子操作类

juc(java.util.concurrent)Java并发工具包中提供了原子操作类,可以提供线程安全的操作,例如:AtomicInteger(原子整数类===>保护整数操作自增、自减的一些线程安全操作)、AtomicBoolean等,它们底层就是采用CAS技术+volatile来实现的。

import java.util.concurrent.atomic.AtomicInteger;
public  class Test {
    // 创建原子整数对象(给一个初始值0)
    private static AtomicInteger i=new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            for (int j = 0; j < 5000 ; j++) {
                i.getAndIncrement();    // 获取并且自增  i++
    //              i.incrementAndGet();    // 自增并且获取  ++i
            }
        });

        Thread t2 = new Thread(()-> {
            for (int j = 0; j < 5000; j++) {
                i.getAndDecrement();    // 获取并且自减 i--
            }
        });

        t1.start();
        t2.start();
    // 让主线程等待,一直等待其他线程不再活动为止    //
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

结果并不会出现整数、负数的情况(利用无锁并发的方式来保证原子整数类中整数信息的线程安全)
在这里插入图片描述

二、 synchronized优化

Java HotSPot虚拟机中,每个对象都有对象头(包括class指针和Mark Word)。Mark Word平时储存这个对象的哈希值、分代年龄,当加锁时,这些信息就根据情况被替换为标记位、线程锁记录指针、重量级锁指针、线程ID等内容

2.1 轻量级锁

如果一个对象虽然有多线程访问,但多线程访问的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。这就好比:

学生(线程A)用课本占座(轻量级锁好比用课本占座,座位好比CPU的使用权),上了半节课,出门了(CPU时间到),回来一看, 发现课本没变,说明没有竞争,继续上他的课。

如果这期间有其它学生(线程B) 来了,会告知(线程A)有并发访问,线程A随即升级为重量级锁,进入重量级锁的流程。【锁膨胀:轻量级锁升级为重量级锁】

而重量级锁就不是用课本占座那么简单了,可以想象线程A走之前,把座位用一个铁栅栏围起来

假设有两个方法同步块,利用同一个对象加锁

  static Object obj=new Object();
    public static void method1(){
        synchronized (obj){
            // 同步块 A
            method2();
        }
    }

    private static void method2() {
        synchronized (obj){
           // 同步块B 
        }
    }

2.2 轻量级锁-无竞争

每个线程的栈帧中都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word(8个字节)

栈帧中锁记录的结构的作用:对一个对象加锁后,需将原来旧的信息暂存到栈帧的锁记录结构中,将来解锁时,再将暂存的Mark Word旧的信息恢复回去

对以上代码的加锁、解锁流程:
在这里插入图片描述

2.3 轻量级锁-锁膨胀

如果在尝试加轻量级锁的过程中,CAS操作无法成功,这是一种情况就是有其他线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁升级为重量级锁。

 static Object obj = new Object();
        public static void method1 () {
            synchronized (obj) {
                // 同步块
            }
        }

在这里插入图片描述

2.4 重量级锁-自旋

重量级锁竞争的时候,还可以使用自选来进行优化,如果当前线程自旋成功(即这个时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。

在Java 6之后自旋锁是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋,总之,比较智能。

● 自旋会占用CPU时间,单核CPU自旋就是浪费(单核CPU无闲置CPU)毫无意义,多核CPU自旋才会发挥优势

● 好比等红灯时汽车是不是熄火,不熄火相当于自旋(等待时间短了划算),熄火相当于阻塞(等待时间长了不划算)

● Java 7之后不能再控制是否开启自旋功能

: 自旋重试成功的情况【当线程2也想加锁(获取monitor)时,发现不能加锁时并不会马上陷入阻塞】
在这里插入图片描述

: 自旋重试失败的情况【线程2不可能无限制的自旋重试,若线程1执行的时间较长,在重试过程中同步代码块还未执行完,重试多次后会放弃重试,然后自己陷入阻塞】
在这里插入图片描述

2.5 偏向锁

假设有两个方法同步块,利用同一个对象加锁
在这里插入图片描述

锁重入:线程1对对象加锁,由于其调用方法2,方法2还是本线程对同一对象加锁,但每次进行锁重入时还是会用CAS再做一次修改Mark Word为线程1的锁记录地址这样的操作

如何优化以上存在的问题?===>JDK 6中引入偏向锁的概念做进一步优化

轻量级锁在没有竞争时(就自己这个线程) , 每次重入仍然需要执行CAS操作。Java 6中引入了偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS.

■ 撤销偏向需要将持锁线程升级为轻量级锁,这个过程中所有线程需要暂停(STW)

■ 访问对象的hashCode也会撤销偏向锁(无锁状态下,对象头中存储的为对象的hashCode;加上偏向锁后,对象头中存的为线程ID,hashCode被放到加锁线程中)

■ 如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程TI的对象仍有机会重新偏向T2, (FL)中J重置对象的Thread ID

■ 撤销偏向和重偏向都是批量进行的,以类为单位

■ 如果撤销偏向到达某个阈值,整个类的所有对象都会变为不可偏向的

■ 可以主动使用-XX:-UseBiasedL ocking禁用偏向锁

可以参考此篇论文: https://www.oracle .com technetwork/java biasedlocking -oopsla2006-wp- 149958.pdf

2.6 synchronized-其他优化

① 减少上锁时间 :同步代码块中尽量短

② 减少锁的粒度 :将一个锁拆分为多个锁提高并发度

例如:
■ ConcurrentHashMap

■ LongAdder(进行计数的原子操作类)分为base和cells 两部分。没有并发争用的时候或者是cells数组正在初始化的时候,会使用CAS来累加值到base,有并发争用,会初始化cells数组,数组有多少个cell,就允许有多少线程并行修改,最后将数组中每个cell累加,再加上base就是最终的值

■ LinkedBlockingQueue 入队和出队使用不同的锁,相对于I inkedBlockingArray只有一个锁效率要高

③ 锁粗化
多次循环进入同步块不如同步块内多次循环
另外JVM可能会做如下优化,把多次append的加锁操作粗化为一次(因为都是对同一个对象加锁,没必要重入多次)

// StringBuffer类是线程安全的【里面的append()方法会有synchronized来进行同步保护】 
   new StringBuffer().append("a").append("b").append("c");   

④ 锁消除 :当对象没有机会被外界用到时,就会将对象上的锁消除掉

JVM会进行代码的逃逸分析,例如某个加锁对象是方法内局部变量,不会被其他线程访问到,这时候就会被即时编译器忽略掉所有同步操作。

⑤ 读写分离

CopyOnWriteArrayList:()读取原始数组的内容;
CopyOnWriteSet:()复制一份,在一个新数组上进行;
因此读操作不同同步,只需要对写操作进行同步即可

参考:
https://wiki.openjdk. java.net/display/HotSpot/Synchronization

http://luojinping.com/2015/07/09/javai)iít1c/

https://www.infoq.cn/article/java-se- 16-synchronized

https://www.jianshu.com/p/9932047a89be

https://www.cnblogs.com/sheeva/p/6366782.html

https://stackoverflow.com/questions/463 12817/does-java-ever-rebias-an-individual-lock

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

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

相关文章

2023年正在使用的设计资源网站分享

这篇文章&#xff0c;也将整理出我今年一直都在使用的设计资源网站&#xff01;作为设计师一定是离不开优质的资源网站的&#xff0c;我自己的话会每天都花一两个小时的时间去浏览自己的收藏的这些资源网站。哪怕只是简单的浏览&#xff0c;也可以在无形中增加自己对设计的“设…

rocketmq延时消息自定义配置

概述 使用的是开源版本的rocketmq4.9.4 rocketmq也是支持延时消息的。 rocketmq一般是4个部分&#xff1a; nameserver&#xff1a;保存路由信息broker&#xff1a;保存消息生产者&#xff1a;生产消息消费者&#xff1a;消费消息 延时消息的处理是在其中的broker中。 但是…

华为认证含金量如何?

一本证书是否有用&#xff0c;还要看它是否被市场所认可。 我们说华为认证HCIP有用&#xff0c;很大一部分还取决于它极高的适用性和权威性。华为是国内最大的生产销售通信设备的民营通信科技公司。 自2013年起&#xff0c;国家对网络安全极度重视&#xff0c;相继把国外的网…

rk3568 开发板Ubuntu系统说明

Ubuntu MinimalUbuntu Minimal系统基于Ubuntu 64bit系统构建&#xff0c;目前发布有Ubuntu18.04这个版本。与Ubuntu Desktop 相比具有以下特性&#xff1a;没有桌面环境&#xff0c;占用资源少&#xff0c;在简化网络管理之后&#xff0c;只需40M内存&#xff1b;针对嵌入式平台…

DFN: Dynamic Filter Networks-动态卷积网络

一、论文信息 论文名称&#xff1a;Dynamic Filter Networks 作者团队&#xff1a;NIPS2016 二、动机与创新 卷积层是通过将上一层的特征映射与一组过滤器进行卷积计算输出特征映射&#xff0c;滤波器是卷积层的唯一参数&#xff0c;通常用反向传播算法在训练中学习&#xff…

一个批量扫描shiro漏洞的工具

Update 1.扫描的判断逻辑,通过返回的rememberMe个数进行判断 2.添加了bypass功能,可以发送随机的请求方法 学习 原理 <1.2.4 shiro550 <1.4.2 shiro721 https://cloud.tencent.com/developer/article/1944738 需要成功登录(目前还没有添加 >1.4.2 换加密方…

kubeadm的部署、Dashboard UI以及连接私有仓库

目录 一、kubeadm 部署 K8S 集群架构 1、环境准备 2、所有节点安装docker 3、所有节点安装kubeadm&#xff0c;kubelet和kubectl 3、部署K8S集群 二、dashboard 部署 1、 安装dashboard 2、使用火狐或者360浏览器访问 三 、安装Harbor私有仓库 四、 内核参数优化方案 …

《FPGA学习》->呼吸灯

&#x1f34e;与其担心未来&#xff0c;不如现在好好努力。在这条路上&#xff0c;只有奋斗才能给你安全感。你若努力&#xff0c;全世界都会为你让路。呼吸灯&#xff0c;简而言之就像人类呼吸一样&#xff0c;有节奏的让LED灯从&#xff1a;灭->微微亮->微亮->亮-&g…

python HZK16字库使用

注&#xff1a; 从个人博客园移植而来 环境&#xff1a; windows7, python2.7 简介 偶然在网上看到热心网友使用python讲微信头像进行了组字&#xff0c;感觉很有意思&#xff0c;就做下研究。 感谢&#xff0c;原文参考: Python玩微信头像组字 需求的相关工具&#xff1a; …

spring cloud gateway 实现redis动态路由及自动项目路由上报

前言 spring cloud gateway默认为内存存储策略&#xff0c;通过配置文件加载的方式生成路由定义信息 可以看到&#xff0c;RouteDefinitionRepository继承了两个父接口&#xff0c;分别为RouteDefinitionLocator和RouteDefinitionWriter&#xff0c;RouteDefinitionLocator定…

Java并发知识点

文章目录1. start()和run()方法的区别&#xff1f;2. volatile关键字的作用&#xff1f;使用volatile能够保证&#xff1a;防止指令重排3. sleep方法和wait方法有什么区别&#xff1f;sleep()方法4. 如何停止一个正在运行的线程&#xff1f;方法一&#xff1a;方法二&#xff1…

MindFusion Diagramming for Java, 最新版 Crack

Diagramming for Java, V4.6.1 A unique Java Swing library for any type of flowchart.您需要的每一个图表功能 图表、方案、图形、网络、算法、树、图表 - 所有这些都是使用 MindFusion Diagramming for Java 工具快速轻松地构建的。结果令人着迷。 Java Dagram 库&#xff…

论文阅读 | Real-Time Intermediate Flow Estimation for Video Frame Interpolation

前言&#xff1a;ECCV2022 快速插帧方法 Real-Time Intermediate Flow Estimation for Video Frame Interpolation 引言 进行视频插帧目前比较常见的方法是基于光流法&#xff0c;分为两个步骤&#xff1a;1.通过光流对齐输入帧&#xff0c;融合对齐的帧 光流并不能直接同于…

CS224W课程学习笔记(三):DeepWalk算法原理与说明

引言 什么是图嵌入&#xff1f; 图嵌入&#xff08;Graph Embedding&#xff0c;也叫Network Embedding&#xff09; 是一种将图数据&#xff08;通常为高维稠密的矩阵&#xff09;映射为低微稠密向量的过程&#xff0c;能够很好地解决图数据难以高效输入机器学习算法的问题。…

arxiv2017 | 用于分子神经网络建模的数据增强 SMILES Enumeration

论文标题&#xff1a;SMILES Enumeration as Data Augmentation for Neural Network Modeling of Molecules论文地址&#xff1a;https://arxiv.org/abs/1703.07076代码地址&#xff1a;https://github.com/Ebjerrum/SMILES-enumeration一、摘要摘要中明显提出&#xff1a;先指…

TCP/IP网络编程——多播与广播

完整版文章请参考&#xff1a; TCP/IP网络编程完整版文章 文章目录第 14 章 多播与广播14.1 多播14.1.1 多播的数据传输方式以及流量方面的优点14.1.2 路由&#xff08;Routing&#xff09;和 TTL&#xff08;Time to Live,生存时间&#xff09;&#xff0c;以及加入组的办法14…

STM32开发(11)----CubeMX配置独立看门狗(IWDG)

CubeMX配置独立看门狗&#xff08;IWDG&#xff09;前言一、独立看门狗的介绍二、实验过程1.STM32CubeMX配置独立看门狗2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对独立看门狗定时器进行配置的方法。门狗本质上是一个定时器&#xff0c;提供了更高的安…

华为云计算之容灾技术

容灾是物理上的容错技术&#xff0c;不是逻辑上的容错同步远程复制&#xff1a;主备距离≤200km&#xff0c;只有在主备设备上都写成功&#xff0c;才会告诉主机写成功&#xff0c;不会丢失数据异步远程复制&#xff1a;主备距离&#xff1e;200km&#xff0c;只要主设备上写成…

掌握MySQL分库分表(二)Mysql数据库垂直分库分表、水平分库分表

文章目录垂直分表拆分方法举例垂直分库水平分表水平分库小结垂直角度&#xff08;表结构不一样&#xff09;水平角度&#xff08;表结构一样&#xff09;垂直分表 需求&#xff1a;商品表字段太多&#xff0c;每个字段访问频次不⼀样&#xff0c;浪费了IO资源&#xff0c;需要…

标题标题标题

图床&#xff08;Typora uPic/PicGo 七牛云&#xff09; 图床&#xff08;Typora uPic/PicGo 七牛云&#xff09; 笔者平时使用 Typora 编写 markdown 文档&#xff0c;文档中常常会放置图片&#xff0c;如果文档不需要分享的话&#xff0c;其实讲图片存放在本地就可以了…