zoukankan      html  css  js  c++  java
  • Java 并发(一) --- CAS

    CAS 原理

          先来看看下面的代码是否可以输出预期的值.开启了两个线程,是否会输出200 呢

    twoThreadConcurrent

          结果由于并发的原因,结果会小于或等于200 , 原因出现在

    count++;

          由于这一行代码存在三个操作: 取值,+1,赋值. 但是由于这三个操作不是原子性的,有可能执行的时候其他线程读取到了,于是就产生了错误的值.

          那么我们在只要在这一行代码加上锁就可以避免并发问题.

    synchronized(this){
        count++;
    }

          但是使用synchronized加锁并不是最佳的选择,因为加锁会伴随性能的问题.

        Synchronized关键字会让没有得到锁资源的线程进入BLOCKED状态,而后在争夺到锁资源后恢复为RUNNABLE状态,这个过程中涉及到操作系统用户模式内核模式的转换,代价比较高。

        尽管Java1.6为Synchronized做了优化,增加了从偏向锁轻量级锁再到重量级锁的过度,但是在最终转变为重量级锁之后,性能仍然较低。

           于是我们通过下面的原子类来解决类,原子类顾名思义就是里面的操作是原子性的.原子类使用的技术就是 CAS .

    auto

           CAS (Compare and Swap) --- 对比并且交换. 什么意思呢?

            下面原理解释摘自参考文章:

    1.在内存地址V当中,存储着值为10的变量。

    2.此时线程1想要把变量的值增加1。对线程1来说,旧的预期值A=10,要修改的新值B=11。

    3.在线程1要提交更新之前,另一个线程2抢先一步,把内存地址V中的变量值率先更新成了11。

    4.线程1开始提交更新,首先进行A和地址V的实际值比较(Compare),发现A不等于V的实际值,提交失败。

    5.线程1重新获取内存地址V的当前值,并重新计算想要修改的新值。此时对线程1来说,A=11,B=12。这个重新尝试的过程被称为自旋

    6.这一次比较幸运,没有其他线程改变地址V的值。线程1进行Compare,发现A和地址V的实际值是相等的。

    7.线程1进行SWAP,把地址V的值替换为B,也就是12。

         从思想上来说,Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。

    CAS 存在的ABA 问题

          通过上面我们知道CAS 向对内存中的数值进行获取比较在进行赋值,只要数值相同就会赋值,但是如果某个数值被更改后又被更改回来,那么此时一样满足交换的条件,那么这样会不会产生问题呢?见

    小灰_进阶_CAS

          同样来自上面文章的总结:

    1. Java语言CAS底层如何实现?

         利用unsafe提供了原子性操作方法。

    2. 什么是ABA问题?怎么解决?

         当一个值从A更新成B,又更新会A,普通CAS机制会误判通过检测。利用版本号比较可以有效解决ABA问题。

     

    参考文章:

    小灰_CAS

    小灰_进阶_CAS

  • 相关阅读:
    setContentView和inflate区别
    eclipse中自动添加注释(作者,时间)
    ImageLoader must be init with configuration before using
    repo用法详解
    SQL 中的N'xx'的作用
    DataRow复制一行到另一个DataTable
    MS SQL SERVER搜索某个表的主键所在的列名
    Win2008 Server R2个人PC化设置
    C# DataTable的詳細用法
    如何解决arcmap中的反走样问题。
  • 原文地址:https://www.cnblogs.com/Benjious/p/9992048.html
Copyright © 2011-2022 走看看