博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2.原子变量 CAS算法
阅读量:6160 次
发布时间:2019-06-21

本文共 3020 字,大约阅读时间需要 10 分钟。

前面提到,使用volatile无法保证 变量状态的原子性操作,所谓原子性,就是不可再分

  如:i++的原子性问题,i++ 的操作实际上分为三个步骤  "读-改-写"

  (1)保存i的值(一个临时变量中)

  (2)递增i

  (3)返回已保存的值

当在并发的条件下执行 i++,

线程1执行 i++,先从主存中 获取 i 的 值(假设初值i=0),还未等 执行i = i + 1,此时线程2进来,也从主存中获取 i 的 值(0)

然后 线程1 执行了 i = i + 1;(i=1) 线程2再执行 i = i + 1(i=1),这种结果是错误的

即使使用 volatile ,保证内存的可见性,也是不管用的,即使在主存中进行修改操作,一样会产生这种错误

 

此时,可以采用 CAS算法 ,CAS算法 是 乐观锁的一种(冲突检测)(hibernate 的乐观锁是 加一个 version 字段,来判断是否发生了并发)

CAS(Compare-And-Swap) 算法 保证数据变量的原子性

CAS 算法是硬件对于并发操作的支持

CAS 包含了三个操作数:

  * ①内存值 V

  * ②预估值 A

  * ③更新值 B

* 当且仅当 V == A 时, V = B; 否则,不会执行任何操作。

过程分析:同样在 并发条件下 执行 i++

  1、线程1 执行 i++,先从主存中获取 i 的值(V=i=0) (设i=0),此时线程2进来,也从主存中 获取 i 的 值(0)

  2、然后线程1 执行 getAndIncrement,即比较和替换一起执行,(过程:再从内存中读取一遍i的值(A=i=0),让 A(0) 与 V(0)进行比较,

发现 V==A,此时,B = i+1,将B的值更新到内存中(V = B) )

  3、然后 线程2 开始执行 getAndIncrement,即比较和替换一起执行,过程 和 上述类似,不过再从内存读一次值,i的值已经变成了 1 ,即A的值也为1

让A(1)与V(0)进行比较比较,发现 V!=A, 不执行任何操作

注:将 V 与 A 比较的意义在于 判断 要更新的值(V)是否发生了改变,如果没有发生改变,则进行 V 的 更新,否则不做任何操作

再发现 V!=A 后,与 synchronize 不一样的 是,这里不会发生阻塞,不会等当前线程执行完后,再由CPU 分配时间去给线程2去执行,

而是不停的 循环发送请求,紧接着再去尝试,再去更新,这也是 CAS算法 比普通同步锁的做法 效率要高的原因

采用CAS算法之后,当有多个线程访问 内存中的共享资源,一次只会有一个线程成功,其他线程都会失败

 

java.util.concurrent.atomic 包下提供了一些原子操作的常用类:里面频繁的使用到了CAS算法来保证变量状态的原子性操作

   AtomicBoolean AtomicInteger AtomicLong AtomicReference

   AtomicIntegerArray AtomicLongArray

   AtomicMarkableReference

   AtomicReferenceArray

   AtomicStampedReference

l核心方法:boolean compareAndSet(expectedValue, updateValue)  (也是CAS里面的核心,即比较和替换一起执行(调用CPU的CAS指令))

 

 

1 /* 2  * 一、i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写” 3  *           int i = 10; 4  *           i = i++; //10 5  *  6  *           (1)保存i的值(一个临时变量中) 7           (2)递增i 8           (3)返回已保存的值 9  * 10  * 二、原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。11  *         1. volatile 保证内存可见性12  *         2. CAS(Compare-And-Swap) 算法保证数据变量的原子性13  *             CAS 算法是硬件对于并发操作的支持14  *             CAS 包含了三个操作数:15  *             ①内存值  V16  *             ②预估值  A17  *             ③更新值  B18  *             当且仅当 V == A 时, V = B; 否则,不会执行任何操作。19  */20 21 public class TestAtomic {22     public static void main(String[] args) {23         24         AtomicDemo ad = new AtomicDemo();25         for(int i = 0;i<10;i++) {26             new Thread(ad).start();27         }28     }29 }30 31 class AtomicDemo implements Runnable {32     //创建原子变量33     private AtomicInteger i = new AtomicInteger(0);34     @Override35     public void run() {36         try {37             Thread.sleep(200);38         } catch (InterruptedException e) {39 40         }41         //查看源码可以发现 循环一直调用compareAndSet(ExceptionValue,UpdateValue)方法,即比较和替换一起执行,42         //并且如果失败了,会不停的去尝试更新(里面使用到CAS算法的)43         System.out.println(i.getAndIncrement());44     }45     46     47 }

 

CAS算法本身不会自旋,但是可以自旋CAS来不停地发送请求,如java.util.concurrent.atomic包,这个包里面提供了一组原子类

  我们来看一段AtomicBoolean中的自旋锁的代码

public final boolean getAndSet(boolean newValue) {   for (;;) {       boolean current = get();       if (compareAndSet(current, newValue))           return current;   }}

转载于:https://www.cnblogs.com/xuzekun/p/7427218.html

你可能感兴趣的文章
我的友情链接
查看>>
网页图表Highcharts实践教程之外层图表区
查看>>
Wireshark数据抓包教程之Wireshark的基础知识
查看>>
apache建立虚拟主机[转载]
查看>>
Lucene系列:(9)搜索结果排序
查看>>
IIS,apche,nginx,301域名重定向设置
查看>>
Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)
查看>>
一次关于cisco的portfast网络故障
查看>>
老司机开车了
查看>>
我的友情链接
查看>>
核密度图
查看>>
Linux应用:FTP
查看>>
Linux命令:iptables网络防火墙
查看>>
第三章 爱的表达
查看>>
获取SQL SERVER某个数据库中所有存储过程的参数
查看>>
在Linux下编译安装Apache2(2)
查看>>
Method Swizzling 处理一类简单的崩溃
查看>>
AngularJS学习!
查看>>
在Eclipse中搭建Python Django
查看>>
struts国际化
查看>>