zoukankan      html  css  js  c++  java
  • 原子操作CAS-最小的线程安全

    原文连接:(http://www.studyshare.cn/blog/details/1166/0
    一、原子操作是什么?

    如果有两个线程分别执行两个操作A和B,从第一个线程执行A操作的角度来看,另外一个线程执行B操作,要么将B操作执行完,要么B操作

    压根儿不执行,那么A操作和B操作对彼此来讲就是原子的。

    java开发工具下载地址及安装教程大全,点这里
    更多深度技术文章,在这里

    二、原子操作如何实现?

    1、使用锁:锁机制就是将一个操作执行完毕后,其他操作获取锁然后继续执行,通过对多个操作进行隔离,从而实现原子操作。

    2、CAS:CAS是Compare And Swap的简称,即:比较并交换。这是当前的处理器基本都支持的一种指令。每个CAS指令包括三个运算符,

    一个内存地址V,一个期望值A和一个新值B,CAS指令执行的时候是去判断这个地址V上的值和期望值A是否相等,相等则将地址V上的值修

    改为新值B,不等则不作任何操作。CAS操作实际实现是在一个循环中不断执行CAS指令,直到成功为止。

    三、为什么要使用原子操作?

    1、我们知道原子操作可以通过锁来实现,但锁是一种粗粒度的操作,使用锁会存在一些问题,例如:(1)当一个线程占用了锁资源,其他

    线程就被阻塞,然而被阻塞的线程的优先级又很高。此时也只能等待锁释放。如果获得锁的线程一致不释放的话那情况就更糟糕了。(2)如

    果有大量的线程来竞争资源,那么CPU就需要花费大量的时间和资源来处理这些竞争。这对CPU这种稀缺资源是不利的。

    2、如果我们要实现一个多线程下的程序计数器。使用锁机制无疑是笨重的。那么CAS就能很好的解决这种需求。

    3、JDK的源码中非常多的类中都使用了CAS操作,了解并清楚CAS操作对阅读JDK源码是必要的。

    四、CAS如何实现线程安全?

    CAS实现线程安全不在代码层面处理,而是交给硬件-CPU和内存,利用CPU的多处理能力,实现硬件层面的阻塞,然后加上volidate变量的

    特性即可实现基于原子操作的线程安全。

    五、CAS实现原子操作的三大问题

    1、ABA问题:因为CAS在操作值的时候先要检查值有没有发生变化,如果没有发生变化则更新,那么所谓ABA问题就是当原来的值是A,改变

    成B,然后又改变成A,那么CAS检查的时候发现值还是初始的A,并没有发生变化。然后实际上却是已经变化了。如何解决ABA问题:加版本

    号,即在A变成B再变成A的时候,每一步操作加一个version,即:1A->2B->3A,这样就可以根据版本号是否有变化即可判断是否发生了ABA问题。

    2、循环时间长、开销大:上面说过是在一个循环中不断执行CAS指令(自旋CAS),如果长时间都不成功的话,则会对CPU带来很大的执行开销。

    3、只能保证一个共享变量的原子操作:即一个CAS操作只能保证一个共享变量的的原子性。如果有多个共享变量则不能使用CAS操作,可使用

    锁。也可以将多个共享变量合并然后使用CAS操作。java1.5之后提供了AtomicReference类来保证引用对象之间的原子性。可以将多个变量放进

    一个对象中然后进行CAS操作。

    六、JDK中常见原子操作类的使用

    1、AtomicInteger

    •int addAndGet(int delta):以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。

    •boolean compareAndSet(int expect,int update):如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。

    •int getAndIncrement():以原子方式将当前值加1,注意,这里返回的是自增前的值。

    •int getAndSet(int newValue):以原子方式设置为newValue的值,并返回旧值。

    2、AtomicIntegerArray

    主要是提供原子的方式更新数组里的整型,其常用方法如下。

    •int addAndGet(int i,int delta):以原子方式将输入值与数组中索引i的元素相加。

    •boolean compareAndSet(int i,int expect,int update):如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值。

    需要注意的是,数组value通过构造方法传递进去,然后AtomicIntegerArray会将当前数组复制一份,所以当AtomicIntegerArray对内部的数组元

    素进行修改时,不会影响传入的数组。

    3、AtomicReference

    原子更新引用类型,更多具体使用可查看jdk文档

    更多原子操作类,在jdk文档java.util.concurrent.atomic包下。

    原创文章,转载请注明出处。
    java开发工具下载地址及安装教程大全,点这里
    更多深度技术文章,在这里

  • 相关阅读:
    docker 安装redis监控redis-stat
    maven 项目依赖打包 提示 package com.。。。。。 does not exist
    docker 建立跨主机网络
    docker-compose 安装mongodb集群==多台服务器
    docker 安装mongodb集群==多台服务器
    博客将近一年半没有更新了
    elasticsearch 使用同义词
    《SpringBoot第一篇:HelloWorld启蒙》
    go学习路线资料
    docker和k8s的概念-IaaS、PaaS、SaaS 的区别
  • 原文地址:https://www.cnblogs.com/darendu/p/11122051.html
Copyright © 2011-2022 走看看