JUC(一):Atomic系列

AtomicInteger:先看看源码

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    //成员属性value得内存地址相对于对象内存地址得偏移量
    private static final long valueOffset;

    static {
        try {
            //通过objectFieldOffset()获取value变量在内存中得偏移
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    //volatile 修饰value,保证数据得可见性
    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    /**
     * Creates a new AtomicInteger with initial value {@code 0}.
     */
    public AtomicInteger() {
    }

    /**
     *获取值
     */
    public final int get() {
        return value;
    }
/**
 * Atomically sets to the given value and returns the old value.
 * 以原子得方式设置给定值,返回旧值
 * @param newValue the new value
 * @return the previous value
 */
public final int getAndSet(int newValue) {
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}

/**
 * Atomically sets the value to the given updated value
 * if the current value {@code ==} the expected value.
 *
 * @param expect the expected value
 * @param update the new value
 * @return {@code true} if successful. False return indicates that
 * the actual value was not equal to the expected value.
 */
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

unsafe.class:

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
       // 通过当前对象和偏移地址 找到实际存储得值
        var5 = this.getIntVolatile(var1, var2);
       //public final native boolean compareAndSwapInt(Object o, long offset, int expected,int x);   //o 为规定对象,offset对象内存得偏移量,通过这个偏移量快速定位并设置或者获取该地段得值,expected 表示当前内存中期望得值,x 表示应该设置得值   // 如果内存中得值 和期待值不一样 就循环 重新去读取,知道读取到最新得值
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

1.什么是偏移地址

偏移地址也称为偏移量,8086/8088 内部ALU只能进行16位得计算,但cpu的地址线是20位,处理的

8086 有20跟地址总线,每一根可以某一时刻传0或1,20位得二进制就是2^20 = 1048576,寻址范围是1M

读取得是20位,但是cpu最大只能处理16位 这咋办?

长度为4 得16 进制用长度为3得16进制表示;

实际地址:  段地址 * 16 + 偏移地址;

* 16 是啥意思?  —   向左移动4位

 demo:1402:100

           1402H * 16 + 0100

        即:14020H –基地址 * 16

      +       0100H –偏移地址

      =       14120H –实际物理地址

2. volatile 只能保证数据得可见性,不能保证数据得原子性

volatile  int  value;

一个线程修改value之后会及时将value值返回到内存中,其他线程读取的时候能保证value是最新得值;

但是读取之后value++;这种操作 就不能保证得到得值 是自己想要得结果.

Atomic 使用了cas 来实现原子性;

 

3. Atomic 不能解决ABA 得问题;

就是一个值由A 边为B,后又被边回A,其他线程在读取的时候并不知道其中得操作过程,只知道一个最终答案;

AtomicStampedReference 保存了一个referance,可以对比是否存在ABA 得问题;

 

    原文作者:JUC
    原文地址: https://blog.csdn.net/waterflying2015/article/details/83657389
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞