2. 原子性 Atomic

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2. 原子性 Atomic相关的知识,希望对你有一定的参考价值。

参考技术A 对于涉及 共享变量 访问的操作,若该操作从其执行线程以外的任意线程来看是 不可分割的 ,那么该操作就是原子操作,称该操作具有原子性

在Java中,对 基础数据类型(除double、long以外)的变量 和 引用变量 的 写操作 都是 原子性 的

Java中的double、long类型变量会占用64位(8字节)的存储空间,32位的Java虚拟机对这种变量的写操作可能会分解为两个步骤实施,比如先写低32位,后写高32位,故不能保证原子性

Java中对任何变量的读操作都是原子性的

Java语言规范特别地规定对于 volatile 关键字修饰的 long/double 类型变量的 写操作 是具有原子性的

可以使用synchronized关键字来保证操作的原子性

原子操作 + 原子操作 != 原子操作

Java源码Atomic部分源码解析

 

AtomicXXX

加了volatile保证了可见性。

本质上这一系列的都是采用的CAS的方式来更新原来的值的。

boolean实际上是用的int值来存储的。

 

AtomicXXXArray

 

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final int base = unsafe.arrayBaseOffset(long[].class);
    private static final int shift;
    private final long[] array;

基本的操作大体的意思应该是:

 

计算出来的地址就是:基础地址+偏移量=最终要定位的元素的地址。

然后Cas操作修改这个地址上的数据。

AtomicReferenceArray里面多了一个arrayFieldOffset,这个域用来支持反序列化的。其次,与AtomicIntegerArray不同,AtomicReferenceArray并没有scale域,取而代之的是shift域。阅读代码可知,其实目的都是计算rawIndex = base + index * scale,只不过AtomicReferenceArray里面把一部分运算转换为等价的位操作(当然前提是scala为2的幂)。(了解更多位操作技巧,可参考Hacker's Delight)。

 

    public final void set(int i, long newValue) 
        unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
    

 

 

AtomicXXXFieldUpdater

 

 

 

 

  • 原子域更新器,一般用于一些原子同步结构中。
    /**
     * Standard hotspot implementation using intrinsics
     */
    private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> 
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private final long offset;
        private final Class<T> tclass;
        private final Class cclass;

 

AtomicIntegerFieldUpdaterImpl构造过程中会目标class,和目标域的访问权限、还要要检查目标域是否为int型,是否由volatile修饰、当然还要获取目标域的偏移量,为后面的CAS操作做准备。

AtomicLongFieldUpdater,结构和AtomicIntegerFieldUpdater类似,有一点区别就是,它有两个实现,根据平台是否支持8字节的CAS操作,来选择不同的实现

AtomicReferenceFieldUpdater和AtomicIntegerFieldUpdater类似的结构,AtomicReferenceFieldUpdater一般用于某些原子数据结构中,支持某些节点的引用域的独立原子更新操作。

其实直接使用AtomicReference也可以完成类似的工作,那么为什么要使用AtomicReferenceFieldUpdater?主要原因还是为了提高性能。假设要设计一个支持原子操作的队列,队列的链接节点必然会进行频繁的操作,如果利用AtomicReference表示这些结点,那么AtomicReference本身的创建过程也需要一些开销,使用AtomicReferenceFieldUpdater可以省去这些开销。辅助创建一个实例,

 

AtomicStampedReference & AtomicMarkableReference

防止ABA问题,分别靠时间戳和Mark标记位来方式ABA问题的发生。

 

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);
        
    
 private static class Pair<T> 
        final T reference;
        final boolean mark;
        private Pair(T reference, boolean mark) 
            this.reference = reference;
            this.mark = mark;
        
        static <T> Pair<T> of(T reference, boolean mark) 
            return new Pair<T>(reference, mark);
        
    

 

 

 

 

 

 

 

 

 

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

原子性atomic/nonatomic

八:并发编程之Atomic&Unsafe魔法类详解

为什么volatile不能保证原子性而Atomic可以?

Java原子性操作之——Atomic包的原理分析

原子性操作原理分析

cocurrent包 原子性数据类型