原子性、CAS操作

Java中的原子性操作

所谓原子性操作,是指执行一系列操作时,这些操作要么全部执行,要么全部不执行,不存在只执行其中一部分的情况。

在设计计数器时一般都先读取当前值,然后+1,再更新。

这个过程是读—改—写的过程,如果不能保证这个过程是原子性的,那么就会出现线程安全问题。

如下代码是线程不安全的,因为不能保证++value是原子性操作。

在这里插入图片描述
那么如何才能保证多个操作的原子性呢?最简单的方法就是使用synchronized关键字进行同步。
在这里插入图片描述
使用synchronized关键字的确可以实现线程安全性,即内存可见性和原子性,但是synchronized是独占锁,没有获取内部锁的线程会被阻塞掉,而这里的getCount方法只是读操作,多个线程同时调用不会存在线程安全问题。

但是加了关键字synchronized后,同一时间就只能有一个线程可以调用,这显然大大降低了并发性。

你也许会问,既然是只读操作,那为何不去掉getCount方法上的synchronized关键字呢?其实是不能去掉的,别忘了这里要靠synchronized来实现value的内存可见性。

那么有没有更好的实现呢?答案是肯定的,下面将讲到的在内部使用非阻塞CAS算法实现的原子性操作类AtomicLong就是一个不错的选择。

Java中的CAS操作

在Java中,锁在并发处理中占据了一席之地,但是使用锁有一个不好的地方,就是当一个线程没有获取到锁时会被阻塞挂起,这会导致线程上下文的切换和重新调度开销。

Java提供了非阻塞的volatile关键字来解决共享变量的可见性问题,这在一定程度上弥补了锁带来的开销问题,但是volatile只能保证共享变量的可见性,不能解决读一改一写等的原子性问题。

CAS即Compare and Swap,其是JDK提供的非阻塞原子性操作,它通过硬件保证了比较一更新操作的原子性。JDK里面的Unsafe类提供了一系列的compareAndSwap*方法,下面以compareAndSwapLong方法为例进行简单介绍。

  • boolean compareAndSwapLong(Object obj,long valueOffset,long expect,long update)方法:其中compareAndSwap的意思是比较并交换。CAS有四个操作数,分别为:对象内存位置、对象中的变量的偏移量、变量预期值和新的值。其操作含义是,如果对象obj中内存偏移量为valueOffset的变量值为expect,则使用新的值update替换旧的值expect。这是处理器提供的一个原子性指令。

关于CAS操作有个经典的ABA问题,具体如下:假如线程I使用CAS修改初始值为A的变量X,那么线程I会首先去获取当前变量X的值(为A),然后使用CAS操作尝试修改X的值为B,如果使用CAS操作成功了,那么程序运行一定是正确的吗?其实未必,这是因为有可能在线程I获取变量X的值A后,在执行CAS前,线程Ⅱ使用CAS修改了变量X的值为B,然后又使用CAS修改了变量X的值为A。所以虽然线程I执行CAS时X的值是A,但是这个A已经不是线程I获取时的A了。这就是ABA问题。

ABA问题的产生是因为变量的状态值产生了环形转换,就是变量的值可以从A到B,然后再从B到A。

如果变量的值只能朝着一个方向转换,比如A到B,B到C,不构成环形,就不会存在问题。

JDK中的AtomicStampedReference类给每个变量的状态值都配备了一个时间戳,从而避免了ABA问题的产生。

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

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

相关文章

python归并排序

归并排序(Merge Sort)是一种经典的排序算法,它采用分治法的一个非常典型的应用。该算法将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。其基本步骤如下: 1…

msckf-vio 跑Euroc数据集,并用evo进行评估

所需材料: Euroc数据集主页:https://projects.asl.ethz.ch/datasets/doku.php?idkmavvisualinertialdatasetsevo评估工具代码:https://github.com/MichaelGrupp/evo向msckf-vio中添加保存位姿的代码,可参考https://blog.csdn.ne…

C++中使用vector保存新建对象中自指指针的问题

问题 在某些场景中(例如并查集),我们需要将新建对象中的指针指向对象自己。例如, struct factor {int data;factor* next;factor(int i) : data(i), next(this){} }; 这样的结构体当然没有问题,如果我们想以类似链表…

分布式锁3: zk实现分布式锁3 使用临时顺序节点+watch监听实现阻塞锁

一 zk实现分布式锁 1.1 使用临时顺序节点 的问题 接上一篇文章,每个请求要想正常的执行完成,最终都是要创建节点,如果能够避免争抢必然可以提高性能。这里借助于zk的临时序列化节点,实现分布式锁 1. 主要修改了构造方法和lock方…

MYSQL 索引使用规则

索引失效 最左前缀法则 where之后写的顺序不重要&#xff0c;存在就可以 范围查询后面的索引查询失效&#xff08;比如>&#xff09;,但是>或者<是不会失效的 不要在索引列上进行运算操作&#xff0c;否则索引失效。 字符串类型字段不加引号索引会失效 尾部模糊匹配…

cgo环境之-安装gcc mingw

下载 到官网下载&#xff1a; 官网 如果你是Windows arm 芯片&#xff0c;可以到这里下载 https://github.com/mstorsjo/llvm-mingw/releases

四、C语言中的数组:数组的输入与元素个数

本章的学习链接如下&#xff1a; 四、C语言中的数组&#xff1a;数组的创建与初始化 1.数组的输入 其实在之前的学习中&#xff0c;我们已经学过了如何用scanf()安全地输入数组&#xff0c;在这一章中我们讲解几种不同的方式。 在 C 语言中&#xff0c;数组的输入通常涉及到…

Spring05

一、Spring事务管理入门 1.1、创建数据库和表 创建一个Spring数据库&#xff0c;在Spring数据库中创建tb_account(账户表)&#xff0c;并初始化数据。 1.2、编写Service层、Mapper层以及调用层 1.2.1、AccountServiceImpl实现了AccountService接口 1.2.2、Mapper层中的代码 1…

数据分析概述

目录 1.数据分析的基本类型&#xff1a;2.数据分析的实现方式&#xff1a;3.机器学习和统计学的区别&#xff1a;3.1统计学3.2机器学习 小结&#xff1a; 1.数据分析的基本类型&#xff1a; 这就不得不提到Gartner分析学价值扶梯模型了&#xff0c;这个模型从复杂度和价值两个…

端口开放问题

端口开放问题 所遇问题 在宿主主机上可以ping通虚拟机ip192.168.27.129&#xff0c;但无法在宿主主机上访问http://192.168.27.129:8080navavcat 16连接mysql时&#xff0c;2002 - Can’t connect to server on ‘192.168.27.129’(100601&#xff09; 原因 以上两个问题&a…

树莓派4B使用ncnn部署yolov5-Lite,推理耗时 247ms 包含前后处理

一. 引言 最近在玩树莓派&#xff0c;想在树莓派上不是一个目标检测算法&#xff0c;大致看了一下&#xff0c;目前开源的大家都在使用yolov5-Lite&#xff0c;使用ncnn去推理加速&#xff0c;于是自己也尝试部署&#xff0c;在此记录一下&#xff0c;个人踩的坑。 二. 版本选…

Matlab三维绘图

绘制三维图plot3 t0:pi/50:10*pi; xsin(t); ycos(t); zt; plot3(x,y,z); 产生栅格数据点meshgrid 这个接口在绘制三维图像里面相当重要&#xff0c;很多时候要将向量变成矩阵才能绘制三维图。 x0:0.5:5; y0:1:10; [X,Y]meshgrid(x,y); plot(X,Y,o); x和y是向量&#xff0c;…

极值和平均值-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第22讲。 极值和平均值&…

GO语言笔记1-安装与hello world

SDK开发工具包下载 Go语言官网地址&#xff1a;golang.org&#xff0c;无法访问Golang中文社区&#xff1a;首页 - Go语言中文网 - Golang中文社区下载地址&#xff1a;Go下载 - Go语言中文网 - Golang中文社区 尽量去下载稳定版本&#xff0c;根据使用系统下载压缩包格式的安装…

【算法】 dp题单练习(寒假正在更新中)

题单链接&#xff1a; https://vjudge.net/contest/574209#overview 目录 1. 洛谷 P1020 导弹拦截 &#xff08;dp二分Dilworth 定理&#xff09; 2. 洛谷 P1439 最长公共子序列&#xff08;二分求最长公共子序列&#xff09; 3. 洛谷 P1854 花店橱窗布置 &#xff08;线…

Illegal hex characters in escape (%) pattern

java.lang.NullPointerException 原因是关键字&#xff1a;5%葡萄糖注射液 其中的百分号通过HttpServletRequest的getParameter传到后端提示空指针异常&#xff0c;然后使用url格式&#xff0c;百分号的十六进制是%25&#xff08;百分号加25&#xff09; 在js代码中加入一段正…

Mybatis实现增删改查的两种方式-配置文件/注解

环境准备 1.数据库表tb_brand -- 删除tb_brand表 drop table if exists tb_brand; -- 创建tb_brand表 create table tb_brand(-- id 主键id int primary key auto_increment,-- 品牌名称brand_name varchar(20),-- 企业名称company_name varchar(20),-- 排序字段ordered int…

【SpringCloud Alibaba笔记】(2)Sentinel实现熔断与限流

Sentinel 概述 官网&#xff1a;https://github.com/alibaba/Sentinel 中文文档&#xff1a;https://sentinelguard.io/zh-cn/docs/introduction.html 类似Hystrix&#xff0c;以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热…

spdlog源码学习

前言 spdlog是一个跨平台c 的开源日志库 &#xff0c;可以head only 使用&#xff0c;包含部分modern c 语法&#xff0c; 更是兼容了c20 format&#xff0c;支持异步和格式化输出&#xff0c;通俗易懂&#xff0c;适合阅读。 源码下载 here 用法 直接贴上了 example.cpp …

四种方式实现[选择性注入SpringBoot接口的多实现类]

最近在项目中遇到两种情况&#xff0c;准备写个博客记录一下。 情况说明&#xff1a;Service层一个接口是否可以存在多个具体实现&#xff0c;此时应该如何调用Service&#xff08;的具体实现&#xff09;&#xff1f; 其实之前的项目中也遇到过这种情况&#xff0c;只不过我采…