10.原子变量

2018-08-08  本文已影响0人  0x70e8

原子变量

原子变量是并发包中的一个并发安全工具,相较于普通变量,它提供了与volatile相同的可见性,相较于volatile变量,它又有对于复合操作的原子性(API中的复合操作)。它是一个实用的并发工具。

原子变量相当于一种泛化的volatile变量,能够支持原子的和有条件的读改写操作。它的原子性不是由锁来提供,而是基于硬件支持的CAS指令。如AtomicInteger表示一个int型值,并提供了set和get方法,这与volatile类型的int变量在读取和写入有着同样的内存语义。

java.util.concurrent包提供了12个原子变量类,分为四类:

最常用的是标量类:AtomicInteger、AtomicLong、AtomICBool饿啊以及AtomicReference。所有这些类都支持CAS,此外AtomicInteger和AtomicLong还提供算术运算。

原子数组类(只支持Integer、Long和Reference版本)中的元素可以实现原子更新。原子数组类为数据的元素提供了volatile类型的访问语义,这是与普通数组不同的地方。

原子变量类是可变类,没有重写hashCode和equals方法,每个示例都是不同的。与其他可变对象相同,他们也不适合做基于散列的容器中的键值。

看一下AtomicInteger的部分源码,了解一下它的实现原理:


package java.util.concurrent.atomic;
import java.util.function.IntUnaryOperator;
import java.util.function.IntBinaryOperator;
import sun.misc.Unsafe;

/**
 * @since 1.5
 * @author Doug Lea
*/
public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    // unsafe类提供了CAS的调用接口,这是原子类的核心基础
    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); }
    }

    // 可以发现,内部存储int值的变量是volatile变量,所以说提供了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);
    }

 // 这是个复合操作,使用的是Unsafe类,底层使用的就是CAS
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }

 
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

 
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

 
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

 
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

 
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }

     
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

    
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
 
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }

    
    public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    
    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    
    public final int getAndAccumulate(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    
    public final int accumulateAndGet(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

   
    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();
    }

}

参考资料

[1] Java并发编程实战

上一篇 下一篇

猜你喜欢

热点阅读