前面提到,使用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指令))

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

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

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

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

2.原子变量 CAS算法的更多相关文章

  1. 3. 原子变量-CAS算法

    1. 是什么 ? 2. CAS算法模拟 package com.gf.demo03; public class TestCompareAndSwap { public static void main ...

  2. 三、原子变量与CAS算法

    原子变量:jdk1.5 后 java.util.concurrent.atomic 包下提供了常用的原子变量: - AtomicBoolean - AtomicInteger - AtomicLong ...

  3. Java多线程-----原子变量和CAS算法

       原子变量      原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题      Java给我们提供了以下几种原子类型: AtomicInteger和Ato ...

  4. 原子变量与CAS算法

    原子变量 为了引出原子变量这个概念,我们先看一个例子. package com.ccfdod.juc; public class TestAtomicDemo { public static void ...

  5. 原子变量与CAS算法小结

    CAS算法 CAS(compare-and-swap)是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问. CAS是一种无锁非阻塞算法的实现. CAS ...

  6. volatile关键字与内存可见性&原子变量与CAS算法

    1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...

  7. 原子变量与CAS算法(二)

    一.锁机制存在的问题 (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. (2)一个线程持有锁会导致其它所有需要此锁的线程挂起. (3)如果一个优先级高的线程等待一个 ...

  8. 计算机程序的思维逻辑 (70) - 原子变量和CAS

    从本节开始,我们探讨Java并发工具包java.util.concurrent中的内容,本节先介绍最基本的原子变量及其背后的原理和思维. 原子变量 什么是原子变量?为什么需要它们呢? 在理解synch ...

  9. Java-JUC(三):原子性变量与CAS算法

    原子性 并发程序正确地执行,必须要保证原子性.可见性以及有序性.只要有一个没有被保证,就有可能会导致程序运行不正确. 原子性:一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行. 可见 ...

随机推荐

  1. VLOOKUP函数 from Excel

    1.VLOOKUP函数是Excel中的一个纵向查找函数,它与LOOKUP函数和HLOOKUP函数属于一类函数,在工作中都有广泛应用,例如可以用来核对数据,多个表格之间快速导入数据等函数功能.功能是按列 ...

  2. [转载]DriverStore文件夹特别大,能删除吗?

    [转载]DriverStore文件夹特别大,能删除吗? 转自博客园https://www.cnblogs.com/lovebing/p/6951833.html 这篇文章,清理完C盘多了20G!不要太 ...

  3. sklearn.svc 参数

    sklearn.svc 参数 sklearn中的SVC函数是基于libsvm实现的,所以在参数设置上有很多相似的地方.(PS: libsvm中的二次规划问题的解决算法是SMO). 对于SVC函数的参数 ...

  4. 移动架构-AOP面向切面编程

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点, ...

  5. 解决电脑开机连不上网问题(Windows检测:远程计算机或设备将不接受连接)

    打开Google Chrome浏览器  -----> 设置 ------> 高级设置 -----> 打开代理设置 -----> 连接 -----> 局域网设置 ----& ...

  6. 三个思路解决413 Request Entity Too Large报错处理

    最近一个项目当中,要求上传图片,并且限制图片大小,虽然在laravel当中已经添加了相关的表单验证来阻止文件过大的上传,然而当提交表单时,还没轮到laravel处理,nginx就先报错了.当你仔细看报 ...

  7. 19年最新 Python0基础学习书籍推荐(内涵PDF地址以及书籍源码)

    去年看过一篇文章,是关于18年的最适合0基础学习的书籍,今年,最新的书籍也已经统计出来.书籍的PDF太过于难找,所以很多PDF都找不到. 仅仅只能找到英文版PDF 本文章统计了18.19并做过对比,在 ...

  8. 高阶函数 filter map reduce

    const app=new Vue({ el:'#app', data:{ books:[{ id:1, name:"算法导论", data: '2006-1', price:39 ...

  9. Airflow怎么删除系统自带的DAG任务

    点击这个按钮 找到dag文件所在路径,并进入路径将其文件删除即可

  10. JavaIO -- Reader 和 Writer

    一.简介 设计Reader和Writer继承层次结构主要是为了国际化.InputStream和OutStream流继承层次结构仅支持8位字节流,并不能很好的处理16位的Unicode字符.由于Unic ...