• Atomic


    类的小工具包,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类.

     传送门 : 并发编程网    Java中的Atomic包使用指南

    一. 使用原子方式更新的指定元素的值

    1. AtomicBoolean

    public class AtomicBoolean extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        // Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        // 记录value字段相对于对象的起始内存地址的字节偏移量,主要是为了在更新操作在内存中找到value的位置,方便比较。
        private static final long valueOffset;
        // 内存值为 int 类型的 0 或 1
        private volatile int value;
    
        static {
            try 
            {
                // 获取value字段相对于对象的起始内存地址的字节偏移量
                valueOffset = unsafe.objectFieldOffset(AtomicBoolean.class.getDeclaredField("value"));
            } catch (Exception ex) {
                throw new Error(ex);
            }
    
        }
        
        public AtomicBoolean(boolean initialValue) {
            value = initialValue ? 1 : 0;
        }
    }

    2. AtomicInteger     

      使用 int 类型的 value 表示实际的值

    3. AtomicLong  

      使用 long 类型的 value 表示实际的值

    // AtomicLongFieldUpdater 中会根据此字段而使用不同的实现类
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

    4. AtomicReference<V>   

      使用 V 类型的 value 表示实际的值

    5. AtomicIntegerArray 

    public class AtomicIntegerArray implements java.io.Serializable {
        private static final long serialVersionUID = -2308431214976778248L;
    
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        // 数组中第一个元素的偏移地址   也就是数组所在的基地址
        private static final int base = unsafe.arrayBaseOffset(int[].class);
        // 
        private static final int shift;
        // 
        private final int[] array;
    
        static {
          // 数组中元素的宽度,int占4个byte,所以此处scale=4
            int scale = unsafe.arrayIndexScale(int[].class);
            if ((scale & (scale - 1)) != 0)
                    // 数据类型规模不是2的幂
                throw new Error("data type scale not a power of two");
            //  numberOfLeadingZeros() 在指定 int 值的二进制补码表示形式中最高位(最左边)的 1 位之前,返回零位的数量
            //  31减去前导零(数字变成二进制后前面0的个数),这里shift 为 2
            shift = 31 - Integer.numberOfLeadingZeros(scale);
        }
        // i 数组下标
        public final int get(int i) {
            return getRaw(checkedByteOffset(i));
        }
        // offset 指定下标的元素相对于 array 的偏移量
        private long getRaw(long offset) {
            return unsafe.getLongVolatile(array, offset);
        }
        // 判断下标是否越界
        private long checkedByteOffset(int i) {
            if (i < 0 || i >= array.length)
                throw new IndexOutOfBoundsException("index " + i);
    
            return byteOffset(i);
        }
        // 返回指定下标的元素相对于 array 的偏移量
        private static long byteOffset(int i) {
            // 基地址 + (第 i 个元素)  i * 4(一个int4个byte)
            return ((long) i << shift) + base;
        }
    
    }

    6. AtomicLongArray

      private final long[] array;

    7. AtomicReferenceArray

    public class AtomicReferenceArray<E> implements java.io.Serializable {
        private static final long serialVersionUID = -6209656149925076980L;
    
        private static final Unsafe unsafe;
        private static final int base;
        private static final int shift;
        private static final long arrayFieldOffset;
        private final Object[] array; // must have exact type Object[]
    
        static {
            try {
                unsafe = Unsafe.getUnsafe();
           // 获取 array 相对于对象的偏移量 
                arrayFieldOffset = unsafe.objectFieldOffset
                    (AtomicReferenceArray.class.getDeclaredField("array"));
                base = unsafe.arrayBaseOffset(Object[].class);
                int scale = unsafe.arrayIndexScale(Object[].class);
                if ((scale & (scale - 1)) != 0)
                    throw new Error("data type scale not a power of two");
                shift = 31 - Integer.numberOfLeadingZeros(scale);
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    
    
    }

     二. 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新(具体实现方式请查看源码)

    8. AtomicIntegerFieldUpdater

      原子方式更新对象中指定Integer类型的字段值

    public abstract class AtomicIntegerFieldUpdater<T> {
    
        // 构造方法同一个package及子类可调用
        protected AtomicIntegerFieldUpdater() {
        }
    
        // AtomicIntegerFieldUpdater是一个抽象类,但是它内部有一个private final类型的默认子类,
        // 所以在调用newUpdater的时候,返回一个 AtomicIntegerFieldUpdaterImpl 实例
        // 一般通过该实例调用相关方法
        @CallerSensitive
        public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
            return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
        }
    }
    // 示例
    public class Demo {
    
        volatile int number;
    
        public static void main(String[] args) {
    
            AtomicIntegerFieldUpdater<Demo> newUpdater = AtomicIntegerFieldUpdater.newUpdater(Demo.class, "number");
            newUpdater.incrementAndGet(new Demo());
        }
    }

    9. AtomicLongFieldUpdater

      原子方式更新对象中指定Long类型的字段值

    public abstract class AtomicLongFieldUpdater<T> {
    
        @CallerSensitive
        public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
                                                               String fieldName) {
            Class<?> caller = Reflection.getCallerClass();
          // 虚拟机是否支持Long类型的CAS操作
            if (AtomicLong.VM_SUPPORTS_LONG_CAS)
                return new CASUpdater<U>(tclass, fieldName, caller);
            else
                return new LockedUpdater<U>(tclass, fieldName, caller);
        }
    }

    10.  AtomicReferenceFieldUpdater

      原子方式更新对象中指定引用类型的字段值

    public abstract class AtomicReferenceFieldUpdater<T,V> {
    
        @CallerSensitive
        public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
                                                                        Class<W> vclass,
                                                                        String fieldName) {
            return new AtomicReferenceFieldUpdaterImpl<U,W>
                (tclass, vclass, fieldName, Reflection.getCallerClass());
        }
    }
  • 相关阅读:
    k8s命令
    git绿色、红色图标不显示的问题
    Git下载
    文档(PDF Word Excel PPT)转HTML前端预览方案
    腾讯云生成临时访问链接
    cron表达式的双重人格:星期和数字到底如何对应?
    Windows下nginx报错解决:CreateFile() "xxx/logs/nginx.pid" failed
    Windows命令行在任意位置启动和退出nginx
    解决博客园TinyMCE模式下内置插入代码块功能不支持Go语言的问题(两个并不完美的解决方案)
    linux系统调用system()函数详解
  • 原文地址:https://www.cnblogs.com/virgosnail/p/9446465.html
Copyright © 2020-2023  润新知