• 原子变量与CAS算法


    原子变量与CAS算法

    一、什么是原子变量?

      原子变量简介

      一般我们在程序中修改一个代码的值会分为3步:读取==》 修改 ==》 回写。在允许多线程的程序中而对于某一资源我们只希望有一个线程操作它,我会想使用全局变量去作为标记变量。两个线程A、B,当A读取完该全局变量后正在修改它的值,而这时B进程正在读取该全局变量,对于B进程而言此全局变量的值和A进程是一样,这样A、B都可以正常进行,就与我们的意愿相违了,所以我们会想是不是可以定义一个变量,将对一个变量值得读取修改回写变成一个不可打断的操作,于是我们就有了原子变量。

      jdk1.5之后引入了java.util.concurrent.atomic工具包,它封装了许多基本数据类型对应的原子变量类,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可将volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。

      java.util.concurrent.atomic 包下提供的一些原子操作的常用类有:
      AtomicBoolean 、AtomicInteger 、AtomicLong 、AtomicReference
      AtomicIntegerArray 、AtomicLongArray
      AtomicMarkableReference
      AtomicReferenceArray
      AtomicStampedReference

      类AtomicBoolean、AtomicInteger、AtomicLong 和AtomicReference 的实例各自提供对相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。

      类AtomicIntegerArray、AtomicLongArray 和AtomicReferenceArray 进一步扩展了原子操作,对这些类型的数组提供了支持。这些类在为其数组元素提供volatile 访问语义方面也引人注目,这对于普通数组来说是不受支持的。

      核心方法:boolean compareAndSet(expectedValue, updateValue)即下面要提到的CAS算法相关

      代码分析

     1 package me.concurrent.atomic;
     2 
     3 import java.util.concurrent.atomic.AtomicInteger;
     4 
     5 /**
     6  * 一、i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”
     7  *           int i = 10;
     8  *           i = i++; //10
     9  * 
    10  *           int temp = i;
    11  *           i = i + 1;
    12  *           i = temp;
    13  * 
    14  * 二、原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。
    15  * 1. volatile 保证内存可见性
    16  * 2. CAS(Compare-And-Swap) 算法保证数据变量的原子性
    17  *     CAS 算法是硬件对于并发操作的支持
    18  *     CAS 包含了三个操作数:
    19  *     ①内存值  V
    20  *     ②预估值  A (当前线程上一次修改的最新旧值)
    21  *     ③更新值  B
    22  *     当且仅当 V == A 时, V = B; 否则,不会执行任何操作。
    23  */
    24 public class TestAtomicDemo {
    25 
    26     public static void main(String[] args) {
    27     AtomicDemo ad = new AtomicDemo();
    28 
    29     for (int i = 0; i < 10; i++) {
    30         new Thread(ad).start();
    31     }
    32     }
    33 
    34 }
    35 
    36 class AtomicDemo implements Runnable {
    37 
    38     // private volatile int serialNumber = 0;
    39 
    40     private AtomicInteger serialNumber = new AtomicInteger(0);
    41 
    42     @Override
    43     public void run() {
    44 
    45     try {
    46         Thread.sleep(200);
    47     } catch (InterruptedException e) {
    48     }
    49 
    50     System.out.println(getSerialNumber());
    51     }
    52 
    53     public int getSerialNumber() {
    54     return serialNumber.getAndIncrement();
    55     }
    56 
    57 }
    View Code

    二、什么是CAS

      CAS简介

      CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问。

      CAS 是一种无锁的非阻塞算法的实现。

      CAS 包含了3 个操作数:
      ①需要读写的内存值V
      ②进行比较的值A(当前线程上一次修改后的旧值)
      ③拟写入的新值B

      当且仅当V 的值等于A 时,CAS 通过原子方式用新值B 来更新V 的值,否则不会执行任何操作。

       代码分析

     1 package me.concurrent.atomic;
     2 
     3 /**
     4  * 模拟 CAS 算法
     5  * CAS算法一般比锁的效率要高,如果当这一次不成功的时候也就是V != A时,他不会造成阻塞,也就是不会放弃CPU给他的执行权,它可以立即再去尝试再去更新
     6  * CAS算法的缺点,一旦更新值失败了之后,它会再次尝试
     7  * CAS算法如果多个线程对共享变量修改时,有且只有一个会成功,其它的都会失败
     8  */
     9 public class TestCompareAndSwap {
    10 
    11     public static void main(String[] args) {
    12     final CompareAndSwap cas = new CompareAndSwap();
    13     for (int i = 0; i < 10; i++) {
    14         new Thread(new Runnable() {
    15         @Override
    16         public void run() {
    17             int expectedValue = cas.get();
    18             boolean b = cas.compareAndSet(expectedValue, (int) (Math.random() * 101));
    19             System.out.println(b);
    20         }
    21         }).start();
    22     }
    23     }
    24 }
    25 
    26 class CompareAndSwap {
    27     private int value;
    28 
    29     /**
    30      * 获取内存值
    31      */
    32     public synchronized int get() {
    33     return value;
    34     }
    35 
    36     /**
    37      * 比较
    38      * 
    39      * @param expectedValue 预估值
    40      * @param newValue 更新值
    41      * @return
    42      */
    43     public synchronized int compareAndSwap(int expectedValue, int newValue) {
    44     int oldValue = value;
    45 
    46     if (oldValue == expectedValue) {
    47         this.value = newValue;
    48     }
    49     return oldValue;
    50     }
    51 
    52     /**
    53      * 设置
    54      * 
    55      * @param expectedValue 预估值
    56      * @param newValue 更新值
    57      * @return
    58      */
    59     public synchronized boolean compareAndSet(int expectedValue, int newValue) {
    60     return expectedValue == compareAndSwap(expectedValue, newValue);
    61     }
    62 }
    View Code

    如果,您对我的这篇博文有什么疑问,欢迎评论区留言,大家互相讨论学习。
    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
    如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
    如果,您对我的博文感兴趣,可以关注我的后续博客,我是【AlbertRui】。

    转载请注明出处和链接地址,欢迎转载,谢谢!

     

  • 相关阅读:
    如何查看Android SDK源码版本
    迁移 Express 到函数计算
    阿里云安全运营中心:DDoS攻击趁虚而入,通过代理攻击已成常态
    Schedulerx2.0支持应用级别资源管理和任务优先级
    Serverless 解惑——函数计算如何安装字体
    一遇到复杂分析查询就卡顿?MySQL分析实例了解一下
    浅谈企业的数据资产管理
    大咖说备份 | 云,让灾备更简单
    急速上线 Serverless 钉钉机器人“防疫精灵”
    Alibaba Cloud Linux 2 LTS 正式发布,提供更高性能和更多保障
  • 原文地址:https://www.cnblogs.com/albertrui/p/8400709.html
Copyright © 2020-2023  润新知