Java原子操作和CAS
为了开发者更方便的编写多线程程序,Java提供了一些原子操作类,在java.util.concurrent.atomic包下。
什么是原子操作?
操作:实现特定功能的1行或N行代码,或一个方法。
原子操作:多线程下,某个线程在执行该操作时,不允许被其他线程打断。
程序运行时,CPU在多个线程中快速的切换,每个线程在运行下一条指令前,都有可能失去CPU的执行权。
对于一个方法或代码块,如果不做任何处理,那么它肯定不是原子操作。
如何保证非原子操作的安全性?
- synchronized
- 加显式锁
但是这两种方式,开销都太大了,
synchronized:基于阻塞的锁机制
- 被阻塞的线程优先级很高
- 热点资源,大量锁竞争,消耗CPU
- 产生死锁,以及其他线程安全问题。
对于一些简单的操作,使用synchronized或者显式锁开销太大了,为了解决这个问题,Java提供了原子操作类。
原子操作类
java.util.concurrent.atomic包下提供了4种类型的操作类:
- 原子更新基本类型
- 原子更新数组
- 原子更新引用
- 原子更新属性
常用API
V get()
获取值void set(V v)
赋值void lazySet(V v)
懒赋值,不能保证对其他线程的“可见性”V getAndSet(V v)
返回旧值,并赋新值boolean compareAndSet(V v1, V v2)
比较并替换,返回是否替换成功
简单例子
public class AtomicBooleanDemo {AtomicInteger ai = new AtomicInteger(0);int i = 0;void add(){//休眠1ms 结果更明显SleepUtil.sleep(1);//原子操作System.out.println(ai.incrementAndGet());//非原子操作System.out.println(++i);}public static void main(String[] args) {AtomicBooleanDemo demo = new AtomicBooleanDemo();for (int i = 0; i < 1000; i++) {new Thread(()->{demo.add();}).start();}}
}
开启1000个线程去对i和ai加1,++i不是原子操作,输出结果最大值小于1000,incrementAndGet()是原子操作,输出结果最大值等于1000。
CAS
什么是CAS?
CAS:Compare and Swap,译为:比较并交换。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。
如果V和A相等,那么就用B来替换。
用Java代码描述如下:
public class CASDemo {int V;boolean compareAndSet(int A, int B) {if (V == A) {V = B;return true;}return false;}
}
这里的compareAndSet肯定是非原子操作。
CAS可以做到:在不加锁的情况下,确保“比较和替换”操作是原子的。
CAS操作是原子的,但不是锁。
它是利用现代处理器中都支持的原子指令来实现的,Java本身不能实现,需要调用本地方法,利用C语言/汇编来实现。
对于简单的“比较和替换”操作,就不要去使用锁,开销太大了,使用CAS性能更高。
存在的问题
ABA问题
通过版本号解决开销问题
只能保证一个共享变量的原子操作
使用AtomicReference解决。
解决ABA问题
ABA问题:假设初始值为A,线程1首先将A改为B,线程2又将B改为A,线程3无法判断A是否被修改过。
Java提供了两个类来解决ABA问题:
AtomicMarkableReference
记录是否被修改过。AtomicStampedReference
记录每次修改的版本号。
AtomicStampedReference除了比较期望值和原值是否相等外,还会判断版本号是否一致,只有都一致,才会进行修改。
AtomicStampedReference例子
public class AtomicStampedReferenceDemo {//构建AtomicStampedReference实例 并设置:初始值和初始版本号AtomicStampedReference<String> asr = new AtomicStampedReference("A", 0);public static void main(String[] args) {AtomicStampedReferenceDemo demo = new AtomicStampedReferenceDemo();//初始版本号int defaultStamp = demo.asr.getStamp();//初始值String defaultValue = demo.asr.getReference();//第一次修改 A > B 版本号 0 > 1 trueboolean oneChange = demo.asr.compareAndSet(defaultValue, "B", defaultStamp, defaultStamp+1);//第二次修改 B > A 版本号 1 > 2 trueboolean twoChange = demo.asr.compareAndSet("B", defaultValue, defaultStamp+1, defaultStamp+2);//第三次修改 A > B 版本号 0 > 1 falseboolean threeChange = demo.asr.compareAndSet(defaultValue, "B", defaultStamp, defaultStamp + 1);}
}
解决只能一个共享变量的问题
- AtomicReference
AtomicReference使用和原子基本类型相似,区别是AtomicReference保存和比较的是对象引用的内存地址。
public class AtomicReferenceDemo {private static class Person{String name;int age;}public static void main(String[] args) {Person person = new Person();person.name = "admin";person.age = 18;AtomicReference<Person> ar = new AtomicReference<>();ar.set(person);Person newPerson = new Person();newPerson.name = "Lisa";newPerson.age = 23;//替换成功 ar内部指向newPersonar.compareAndSet(person, newPerson);Person arPerson = ar.get();System.out.println(arPerson == newPerson);//trueSystem.out.println(arPerson.name);//LisaSystem.out.println(person.name);//admin}
}
Java原子操作和CAS相关推荐
- Java原子操作Atomic
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/120854796 本文出自[赵彦军的博客] Java线程安全StampedLock ...
- JAVA并发编程: CAS和AQS
说起JAVA并发编程,就不得不聊聊CAS(Compare And Swap)和AQS了(AbstractQueuedSynchronizer). CAS(Compare And Swap) 什么是CA ...
- Java 锁之 CAS
什么是CAS(compare and swap)? CAS(Compare & Set,或是 Compare & Swap),即比较并交换,也是实现我们平时所说的自旋锁或乐观锁的核心操 ...
- 【面试篇】Java多线程并发-Java中的CAS机制算法
Java中的CAS机制算法 a.CAS例子 再讲解CAS机制之前,先来看一道经典的并发执行1000次递增的问题: public class Test { public static int count ...
- 【高并发】java中的CAS,你需要知道的东西
1.概述 转载:添加链接描述 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库乐观锁的一个常见示例 使用java中的原子操作实现网 ...
- JAVA 中的 CAS
原文地址:https://www.xilidou.com/2018/02/01/java-cas/ CAS 是现代操作系统,解决并发问题的一个重要手段,最近在看 eureka 的源码的时候.遇到了很多 ...
- Java中的CAS操作
Java中的CAS的含义 CAS即是Compare and Swap ,它是JDK提供的非阻塞原子性操作,它通过硬件保证了比较一更新操作的原子性.CAS 操作包含三个操作数-内存位置(V).预期原值( ...
- Java中的CAS以及AQS实现原理
Java中的CAS实现原理 什么是CAS? 在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令. 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将 ...
- Java原子操作类AtomicInteger应用场景
参考文章:Java原子操作类AtomicInteger应用场景 感谢作者分享!
最新文章
- RxJava响应式编程学习笔记
- html列表穿插广告怎么实现,基于innerHTML中的script广告实现代码[广告全部放在一个js里面]...
- 海康开放平台音视频方案对比(rtsp、http-flv、hls、rtmp)
- Winform中使用OpenFileDialog选择文件打开并获取文件路径
- 最详细易懂的CRC-16校验原理(附源程序)
- 多帧点云数据拼接合并_自动驾驶:Lidar 3D传感器点云数据和2D图像数据的融合标注...
- 鸿蒙2.0beta报名,鸿蒙OS 2.0 Beta版系统在哪报名-报名方法介绍
- pushlet单播与多播
- [HNOI2008 Tree]
- mysql下删改增语句_MySQL增删改查
- Android Studio一直显示Building“project name”Gradle project info问题详解
- plc vb c语言编程,[转载]VB6.0在PLC和上位机通讯中的应用【工控老鬼分享】
- 决策树结果可视化中文乱码问题解决方案
- Excel文件编辑保护如何取消?
- React:Redux和Flux
- C++核心准则R.33: 表达函数会重置widget时,使用unique_ptr(widget)​作参数
- 乐视更新APP,图标显示欠122亿,反向营销?贾跃亭将回国造梦?
- iPhone 全系尺寸大全
- Unity2019,2020安装教程
- JS面试系列之节流