zoukankan      html  css  js  c++  java
  • Java深入学习02:CAS 算法以及低层原理

    Java深入学习02:CAS 算法以及低层原理

    参考文章:https://www.cnblogs.com/linkworld/p/7819270.html;已经描述很清晰

     

    i++ 的原子性问题

    1. i++的操作实际上分为三个步骤: "读-改-写";
    2. 原子性: 就是"i++"的"读-改-写"是不可分割的三个步骤;
    3. 原子变量: JDK1.5 以后, java.util.concurrent.atomic包下,提供了常用的原子变量;
      • 原子变量中的值,使用 volatile 修饰,保证了内存可见性;
      • CAS(Compare-And-Swap) 算法保证数据的原子性;
    int i = 10;
    i = i++;  // 此时, i=10
    
    执行步骤:
    int temp = i;
    i = i + 1;
    i = temp;
    
    
    // 测试类
    public class TestAtomicDemo{
        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 int serialNumber = 0;
    
        public void run(){
    
            try{
                Thread.sleep(200);
            }catch(InterruptedException e){
    
            }
    
            System.out.println(Thread.currentThread().getName() + ":" + getSerialNumber());
        }
    
        public int getSerialNumber(){
            return serialNumber++;
        }
    }

    // 改进: 使用原子变量
    class AtomicDemo implements Runnable{
    
        private AtomicInteger serialNumber = new AtomicInteger();
    
        public void run(){
            try{
                Thread.sleep(200);
            }catch(InterruptedException e){
    
            }
    
            System.out.println(Thread.currentThread().getName()+":"+getSerialNumber());
        }
    
        public int getSerialNumber(){
            // 自增运算
            return serialNumber.getAndIncrement();
        }
    }

    CAS 算法

    • CAS(Compare-And-Swap) 算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于
      管理对共享数据的并发访问;
    • CAS 是一种无锁的非阻塞算法的实现;
    • CAS 包含了三个操作数:
      • 需要读写的内存值: V
      • 进行比较的预估值: A
      • 拟写入的更新值: B
      • 当且仅当 V == A 时, V = B, 否则,将不做任何操作;
    // 模拟CAS 算法
    class CompareAndSwap{
        private int value;
    
        // 获取内存值
        public synchronized int get(){
            return value;
        }
    
        // 无论更新成功与否,都返回修改之前的内存值
        public synchronized int compareAndSwap(int expectedValue, int newValue){
            // 获取旧值
            int oldValue = value;
    
            if(oldValue == expectedValue){
                this.value = newValue;
            }
    
            // 返回修改之前的值
            return oldValue;
        }
    
        // 判断是否设置成功
        public synchronized boolean compareAndSet(int expectedValue, int newValue){
            return expectedValue == compareAndSwap(expectedValue, newValue);
        }
    }
    
    public class TestCompareAndSwap{
        public static void main(String[] args){
            final CopareAndSwap cas = new CompareAndSwap();
    
            for(int i=0; i<10; i++){
                // 创建10个线程,模拟多线程环境
                new Thead(new Runnable(){
                    public void run(){
                        int expectedValue = cas.get();
    
                        boolean b = cas.compareAndSet(expectedValue, (int)(Math.random()*100));
                        System.out.println(b);
                    }
                }).start();
            }
        }
    }

    CAS优点

      1- 避免优先级倒置和死锁等危险,竞争比较便宜,协调发生在更细的粒度级别,允许更高程度的并行机制等。

    CAS缺点 

      1- 循环时间长CPU开销很大;

      2- 只能保证一个共享变量的原子性

      3- 引出了ABA问题

    CAS算法底层原理

      我们以AtomicIntegerd 的getAndIncrement方法为例,进行简要分析。

    ##AtomicInteger类
    
        private static final Unsafe unsafe = Unsafe.getUnsafe();
    
        private static final long valueOffset;//AtomicInteger 对象 value 属性偏移地址
    
        public final int getAndIncrement() {
            return unsafe.getAndAddInt(this, valueOffset, 1);
        }
    
    
    ##Unsafe类
        public final int getAndAddInt(Object var1, long var2, int var4) {
            int var5;
            do {
                var5 = this.getIntVolatile(var1, var2);
            } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    
            return var5;
        }
    
        @CallerSensitive
        public static Unsafe getUnsafe() {
            Class var0 = Reflection.getCallerClass();
            if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
                throw new SecurityException("Unsafe");
            } else {
                return theUnsafe;
            }
        }
    
    
    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
  • 相关阅读:
    随记(二)--是否能打开手机某个应用
    asp.net 登陆后在ashx处理程序中获取不到Session
    Highcharts Pie 饼图提示标签IE下重叠解决方法,及json数据绑定方法
    怎样用ZBrush对模型进行渲染(二)
    怎样用ZBrush对模型进行渲染
    ZBrush中该如何调节多个SubTool
    如何用ZBrush快速绘制身体
    MIDI信息为什么不能通过FL Studio输出
    怎样制作FL Studio步进音序器中的节奏
    不同材质怎么通过ZBrush赋予同一个模型上
  • 原文地址:https://www.cnblogs.com/wobuchifanqie/p/11815684.html
Copyright © 2011-2022 走看看