Atomic

Posted virgosnail

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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());
    }
}

 

以上是关于Atomic的主要内容,如果未能解决你的问题,请参考以下文章

并发包学习之-atomic包

std::atomic 与另一个字符联合

Java多线程之Atomic:原子变量与原子类

并发之atomic原子操作

原子读取然后用 std::atomic 写入

为啥我使用 openMP atomic 的并行代码比串行代码花费更长的时间?