zoukankan      html  css  js  c++  java
  • Atomic

    CAS原语

    CAS(compare and swap)是一组原语指令,用来实现多线程下的变量同步。
        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }

    在 x86 下的指令CMPXCHG实现了CAS,前置LOCK既可以达到原子性操作。截止2013,大部分多核处理器均支持CAS。

    CAS原语有三个参数,内存地址,期望值,新值。如果内存地址的值==期望值,表示该值未修改,此时可以修改成新值。否则表示修改失败,返回false,由用户决定后续操作。
    在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。

    ABA 问题

    AtomicMarkableReference/AtomicStampedReference在解决“ABA问题”上很有用
    thread1意图对val=1进行操作变成2,cas(*val,1,2)。
    thread1先读取val=1;thread1被抢占(preempted),让thread2运行。
        public final int getAndSet(int newValue) {
            for (;;) {
           //先读取val=1
    int current = get();
           //线程被抢占
    if (compareAndSet(current, newValue)) return current; } }

    thread2 修改val=3,又修改回1。

    thread1继续执行,发现期望值与“原值”(其实被修改过了)相同,完成CAS操作。

    使用CAS会造成ABA问题,特别是在使用指针操作一些并发数据结构时。
    解决方案
    ABAʹ:添加额外的标记用来指示是否被修改。 

    AtomicIntegerFieldUpdater<T>

    AtomicLongFieldUpdater<T>

    AtomicReferenceFieldUpdater<T,V>

    是基于反射的原子更新字段的值。

    相应的API也是非常简单的,但是也是有一些约束的。

    (1)字段必须是volatile类型的!volatile到底是个什么东西。

    (2)字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。

    (3)只能是实例变量,不能是类变量,也就是说不能加static关键字。

    (4)只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。

    (5)对于AtomicIntegerFieldUpdaterAtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。 

    import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;   
      
    public class AtomicIntegerFieldUpdaterDemo {   
      
       class DemoData{  
           public volatile int value1 = 1;  
           volatile int value2 = 2;  
           protected volatile int value3 = 3;  
           private volatile int value4 = 4;  
       }  
        AtomicIntegerFieldUpdater<DemoData> getUpdater(String fieldName) {  
            return AtomicIntegerFieldUpdater.newUpdater(DemoData.class, fieldName);  
        }  
        void doit() {  
            DemoData data = new DemoData();  
            System.out.println("1 ==> "+getUpdater("value1").getAndSet(data, 10));  
            System.out.println("3 ==> "+getUpdater("value2").incrementAndGet(data));  
            System.out.println("2 ==> "+getUpdater("value3").decrementAndGet(data));  
            System.out.println("true ==> "+getUpdater("value4").compareAndSet(data, 4, 5));  
        }  
        public static void main(String[] args) {  
            AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo();  
            demo.doit();  
        }  
    }   

    在上面的例子中DemoData的字段value3/value4对于AtomicIntegerFieldUpdaterDemo类是不可见的,因此通过反射是不能直接修改其值的。

    AtomicMarkableReference类描述的一个<Object,Boolean>的对,可以原子的修改Object或者Boolean的值,这种数据结构在一些缓存或者状态描述中比较有用。这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量。

     AtomicStampedReference类维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。对比AtomicMarkableReference类的<Object,Boolean>,AtomicStampedReference维护的是一种类似<Object,int>的数据结构,其实就是对对象(引用)的一个并发计数。但是与AtomicInteger不同的是,此数据结构可以携带一个对象引用(Object),并且能够对此对象和计数同时进行原子操作。

  • 相关阅读:
    杭电OJ 输入输出练习汇总
    七月读书笔记
    情报分析报告阅读笔记
    情报研究与分析入门阅读笔记
    旁观者攻击
    域前置技术相关学习
    CC攻击和C2的区别
    DNS投毒学习分析总结
    数字证书2.0版本学习总结
    《在树洞里》-感悟
  • 原文地址:https://www.cnblogs.com/wade-luffy/p/5766526.html
Copyright © 2011-2022 走看看