• JUC学习笔记--Atomic原子类


    J.U.C 框架学习顺序 http://blog.csdn.net/chen7253886/article/details/52769111

    Atomic 原子操作类包

    Atomic包 主要是在多线程环境下,无锁的进行原子操作。核心操作是基于UnSafe类实现的CAS方法

    CAS

    CAS: compareAndSwap :传入两个值:期望值和新值,判断原有值与期望值相等,则给其赋新值,否则不做任何操作。

    CAS硬件支持

    现代的CPU提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰。

    Atomic源码

    以AtomicInteger为例(AtomicBoolean也是把boolen转为int)

    public class AtomicInteger extends Number implements java.io.Serializable {
        //序列化相关
        private static final long serialVersionUID = 6214790243416807050L;
        //Unsafe类
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        //内存地址偏移量
        private static final long valueOffset;
        static {
          try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
          } catch (Exception ex) { throw new Error(ex); }
        }
        //value值,因为无锁使用volatile保证线程加载到最新的值
        private volatile int value;
        //初始化
        public AtomicInteger(int initialValue) {
            value = initialValue;
        }
        public AtomicInteger() {
        }
        //获取当前值
        public final int get() {
            return value;
        }
        //赋值
        public final void set(int newValue) {
            value = newValue;
        }
        //延迟赋值,不保证新的赋值能立即被其他线程获取到
        public final void lazySet(int newValue) {
            unsafe.putOrderedInt(this, valueOffset, newValue);
        }
        //返回旧值并赋新值
        public final int getAndSet(int newValue) {
            for (;;) {// 等同于while(true)
                int current = get();//获取旧值
                if (compareAndSet(current, newValue))//以CAS方式赋值,直到成功返回
                    return current;
            }
        }
        //对比期望值与value,不同返回false。相同将update赋给value 返回true
        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
        //与compareAndSet实现相同(可能为了以后更改)
        public final boolean weakCompareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
        //自增 i++
        public final int getAndIncrement() {
            for (;;) {
                int current = get();
                int next = current + 1;
                if (compareAndSet(current, next))
                    return current;
            }
        }
        //自减 i--
        public final int getAndDecrement() {
            for (;;) {
                int current = get();
                int next = current - 1;
                if (compareAndSet(current, next))
                    return current;
            }
        }
        //自定义增量数
        public final int getAndAdd(int delta) {
            for (;;) {
                int current = get();
                int next = current + delta;
                if (compareAndSet(current, next))
                    return current;
            }
        }
    
        //++i 返回自增后的值
        public final int incrementAndGet() {
            for (;;) {
                int current = get();
                int next = current + 1;
                if (compareAndSet(current, next))
                    return next;
            }
        }
        
        //--i 返回减少后的值
        public final int decrementAndGet() {
            for (;;) {
                int current = get();
                int next = current - 1;
                if (compareAndSet(current, next))
                    return next;
            }
        }
    
        //返回加上delta后的值
        public final int addAndGet(int delta) {
            for (;;) {
                int current = get();
                int next = current + delta;
                if (compareAndSet(current, next))
                    return next;
            }
        }
    
        /**
         * Returns the String representation of the current value.
         * @return the String representation of the current value.
         */
        public String toString() {
            return Integer.toString(get());
        }
    
    
        public int intValue() {
            return get();
        }
    
        public long longValue() {
            return (long)get();
        }
    
        public float floatValue() {
            return (float)get();
        }
    
        public double doubleValue() {
            return (double)get();
        }
    
    }
    

    CAS的ABA问题

    ABA问题:有两个线程,x线程读取值为A ,y线程读取值为A 并赋值为B,B线程再修改会A,此时x线程以A为旧值并赋新值仍然是成功的,
    因为线程x不知道变量值经过A->B->A的修改。

    AtomicStampedReference 解决ABA问题

    先看看如何使用:

            AtomicStampedReference<Integer> asr= new AtomicStampedReference<Integer>(1,0);
            int stamp= asr.getStamp();
            System.out.println(asr.compareAndSet(1,2,stamp,stamp+1));//true
            System.out.println(asr.compareAndSet(2,1,stamp,stamp+1));//false
            System.out.println(asr.compareAndSet(1,1,stamp+1,stamp+2));//false
            System.out.println(asr.getReference());//2
    

    对比AtomicInteger,可见AtomicStampedReference的构造函数多了一个参数、compareAndSet方法多了两个参数,看一下源码:

        //对比AtomicInteger构造函数多了stamp参数
        public AtomicStampedReference(V initialRef, int initialStamp) {
            pair = Pair.of(initialRef, initialStamp);
        }
    
    
        private static class Pair<T> {
            final T reference;
            final int stamp;
            private Pair(T reference, int stamp) {
                this.reference = reference;
                this.stamp = stamp;
            }
            static <T> Pair<T> of(T reference, int stamp) {
                return new Pair<T>(reference, stamp);
            }
        }
        //对比AtomicInteger value由int 改为Pair<V>
        private volatile Pair<V> pair;
    
        public boolean compareAndSet(V   expectedReference,
                                     V   newReference,
                                     int expectedStamp,
                                     int newStamp) {
            Pair<V> current = pair;
            return
                expectedReference == current.reference &&        //判断期望值与旧值是否相同
                expectedStamp == current.stamp &&   //判断期望版本戳与旧版本戳是否相同
                ((newReference == current.reference &&
                  newStamp == current.stamp) ||    //如果值和戳没变化不执行下一行cas赋值代码
                 casPair(current, Pair.of(newReference, newStamp)));//cas赋值代码
        }
        //还是调用unsafe类
        private boolean casPair(Pair<V> cmp, Pair<V> val) {
            return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
        }
    
  • 相关阅读:
    Python上下文管理器
    面向对象(三)【类的特殊成员及高级特性】
    面向对象(二)【类的成员及修饰符】
    面向对象(一)【“类与对象”的概念及特性】
    leetcode【14题】Longest Common Prefix
    Spring Cloud之Zuul
    Spring Cloud之Hystrix
    SpringCloud之Eureka、Ribbon
    synchronized块中的wait()、nofity()、nofityAll()方法
    IP的分类以及子网划分、网络设置
  • 原文地址:https://www.cnblogs.com/javanoob/p/juc-atomic.html
Copyright © 2020-2023  润新知