原子变量&&CAS算法
来源:互联网 发布:淘宝网薄印花半大开衫 编辑:程序博客网 时间:2024/05/17 04:33
进入今天的主题先看一段代码和代码的输出结果
class AtomicDemo implements Runnable{ private int serialNumber=0; public int getSerialNumber() { return serialNumber++; } @Override public void run() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getSerialNumber()); }}public class TestAutomic { public static void main(String[] args) { AtomicDemo atomicDemo=new AtomicDemo(); for (int i = 0; i < 10; i++) { new Thread(atomicDemo).start(); } }}
可以看到在多线程的情况下serialNumber++操作出现了问题,分析下为什么会出现这个问题?
主内存和工作内存的区别:
根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
由于serialNumber++操作,会在内存中产生一个临时的变量temp,首先将temp=serialNumber,然后serialNumber=serialNumber+1操作,最后serialNumber=1去更新主存的值;但是在多线程并发的情况下,线程2拿到的serialNumber的值可能是0,可能不是serialNumber=serialNumber+1操作后的值。由于原子性的操作是不可以分割的,但是++的操作把serialNumber++分割了,在多线程的情况下,所以出现了这种情况。在Volatile关键字内存可见的情况下,输出的结果还是一样的,因为Volatile关键字不能保证变量状态的“原子性操作”,怎么解决这个问题,先看2个概念。
CAS算法:
CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器 操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并 发访问。
CAS 是一种无锁的非阻塞算法的实现。
CAS 包含了 3 个操作数:
需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
当且仅当 V 的值等于 A 时,CAS 通过原子方式用新值 B 来更新 V 的 值,否则不会执行任何操作。
原子变量:
类的小工具包,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。
类 AtomicBoolean、AtomicInteger、AtomicLong 和 AtomicReference 的实例各自提供对 相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。
AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray类进一步扩展了原子操 作,对这些类型的数组提供了支持。这些类在为其数组元素提供 volatile 访问语义方 面也引人注目,这对于普通数组来说是不受支持的。
核心方法:boolean compareAndSet(expectedValue, updateValue)
java.util.concurrent.atomic包下提供了一些原子操作的常用类:
AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference AtomicIntegerArray、AtomicLongArray
AtomicMarkableReference
AtomicReferenceArray
AtomicStampedReference
看上图的下方的左边部分,V=0 拿到是主存的值,A=0是作为比较的值,B=1是在当前的线程1,V+1之后之后的值(通过B来更新主存的值),右边部分 V=0 在多线程的情况下拿到的可能是0,A=1是在线程1(多线程的情况下),+1之后改之后的值,B=1是当前的线程2,V+1之后的值,V!=A,此时不能拿B去更新主存的值,说白了就是在多个线程的情况下,只有一个线程会执行成功。但是由于CAS 是一种无锁的非阻塞算法的实现,压根不会放弃CPU给它的执行权,执行的效率非常的高,又会去执行一遍,取主存拿值,然后在计算更新值。这个要清楚的是CAS算法是一种硬件对并发的支持(看概念)。
修改后的代码
class AtomicDemo implements Runnable{ //private int serialNumber=0; private AtomicInteger atomicInteger=new AtomicInteger(); public int getSerialNumber() { return atomicInteger.getAndIncrement(); //自增加1 } @Override public void run() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getSerialNumber()); }}public class TestAutomic { public static void main(String[] args) { AtomicDemo atomicDemo=new AtomicDemo(); for (int i = 0; i < 10; i++) { new Thread(atomicDemo).start(); } }}
原子变量保证了数据的原子性,volatile关键字内存可见性。
说到最后,到底CAS算法是怎么实现的? 下篇博客介绍。
- 原子变量&&CAS算法
- 原子变量CAS算法
- 原子变量和CAS算法
- 17.原子变量 CAS算法
- 原子变量与CAS算法小结
- 原子变量和CAS算法简单介绍
- 多线程之原子变量CAS算法(二)
- 多线程之原子变量CAS算法(二)
- 原子变量 和cas 原理
- 免锁算法----原子变量
- java并发中的原子变量和原子操作以及CAS介绍
- java中CAS算法保证原子性 无锁编程
- java——保证原子性操作的CAS算法
- 原子变量
- 原子变量
- Intel处理器CAS原子指令
- memcache CAS实现原子操作
- java并发编程4:原子变量与非阻塞算法
- Eclipse在线安装 报错 An error occurred while collecting items to be installed
- 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型及原型设计
- To solve machine learning problems
- Leetcode刷题记—— 60. Permutation Sequence(排列序列)
- 面试(Java)
- 原子变量&&CAS算法
- MySQL二进制日志格式对复制的影响
- 浅谈散列
- 转成数组的通用函数
- Nginx静态资源简单配置
- 20170304-java
- LeapMotion驱动安装教程
- MySQL主从复制实战
- 二叉树层级遍历并按行打印