zoukankan      html  css  js  c++  java
  • 原子变量与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】。

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

     

  • 相关阅读:
    Andrew Ng机器学习week4(Neural Networks: Representation)编程习题
    linux系统下crontab 配置启动定时任务
    在python中配置tornado服务
    在python中Flask配置服务
    ltp的使用
    查看文件内容- 删除某个运行程序的所有进程-nohup后台执行程序
    机器学习和深度学习资料整理
    配置linux服务器和pycharm的连接
    计算 24 点是一种扑克牌益智游戏,随机抽出 4 张扑克牌,通过加 (+) ,减 (-) ,乘 ( * ), 除 (/) 四种运算法则计算得到整数 24 ,本问题中,扑克牌通过如下字符或者字符串表示,其中,小写 joker 表示小王,大写 JOKER 表示大王:
    机器人的运动范围 剑指offer66题
  • 原文地址:https://www.cnblogs.com/albertrui/p/8400709.html
Copyright © 2011-2022 走看看