JDK源码 -- AtomicInteger

2019-08-19  本文已影响0人  TomyZhang

一、概念

类定义:

public class AtomicInteger extends Number implements java.io.Serializable

特点:

二、使用

//TestAtomicInteger
public class TestAtomicInteger {
    private static final String TAG = "TestAtomicInteger";
    private AtomicInteger atomicInteger = new AtomicInteger(100);

    public void testGet() {
       int value =  atomicInteger.get();
        Log.d(TAG, "zwm, get: " + value);
    }

    public void testGetAndIncrement() {
        int value = atomicInteger.getAndIncrement();
        Log.d(TAG, "zwm, getAndIncrement 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, getAndIncrement 2: " + value);
    }

    public void tesGetAndDecrement() {
        int value = atomicInteger.getAndDecrement();
        Log.d(TAG, "zwm, getAndDecrement 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, getAndDecrement 2: " + value);
    }

    public void testGetAndAdd() {
        int value = atomicInteger.getAndAdd(10);
        Log.d(TAG, "zwm, getAndAdd 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, getAndAdd 2: " + value);
    }

    public void testGetAndSet() {
        int value = atomicInteger.getAndSet(999);
        Log.d(TAG, "zwm, getAndSet 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, getAndSet 2: " + value);
    }

    public void testIncrementAndGet() {
        int value = atomicInteger.incrementAndGet();
        Log.d(TAG, "zwm, incrementAndGet 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, incrementAndGet 2: " + value);
    }

    public void testDecrementAndGet() {
        int value = atomicInteger.decrementAndGet();
        Log.d(TAG, "zwm, decrementAndGet 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, decrementAndGet 2: " + value);
    }

    public void testAddAndGet() {
        int value = atomicInteger.addAndGet(10);
        Log.d(TAG, "zwm, addAndGet 1: " + value);
        value = atomicInteger.get();
        Log.d(TAG, "zwm, addAndGet 2: " + value);
    }

    public void testSet() {
        atomicInteger.set(100);
        Log.d(TAG, "zwm, set: " + atomicInteger.get());
    }

    public void testCompareAndSet() {
        boolean result = atomicInteger.compareAndSet(99, 999);
        Log.d(TAG, "zwm, compareAndSet, result: " + result);
        result = atomicInteger.compareAndSet(100, 1000);
        Log.d(TAG, "zwm, compareAndSet, result: " + result);
        Log.d(TAG, "zwm, compareAndSet: " + atomicInteger.get());
    }

    public void testIntValue() {
        int value = atomicInteger.intValue();
        Log.d(TAG, "zwm, intValue: " + value);
    }
}

//测试代码
private void testMethod() {
    Log.d(TAG, "zwm, testMethod");
    TestAtomicInteger testAtomicInteger = new TestAtomicInteger();
    testAtomicInteger.testGet();
    testAtomicInteger.testGetAndIncrement();
    testAtomicInteger.tesGetAndDecrement();
    testAtomicInteger.testGetAndAdd();
    testAtomicInteger.testGetAndSet();
    testAtomicInteger.testIncrementAndGet();
    testAtomicInteger.testDecrementAndGet();
    testAtomicInteger.testAddAndGet();
    testAtomicInteger.testSet();
    testAtomicInteger.testCompareAndSet();
    testAtomicInteger.testIntValue();
}

//输出log
2019-08-21 14:35:04.596 zwm, testMethod
2019-08-21 14:35:04.598 zwm, get: 100
2019-08-21 14:35:04.598 zwm, getAndIncrement 1: 100
2019-08-21 14:35:04.598 zwm, getAndIncrement 2: 101
2019-08-21 14:35:04.598 zwm, getAndDecrement 1: 101
2019-08-21 14:35:04.598 zwm, getAndDecrement 2: 100
2019-08-21 14:35:04.598 zwm, getAndAdd 1: 100
2019-08-21 14:35:04.598 zwm, getAndAdd 2: 110
2019-08-21 14:35:04.599 zwm, getAndSet 1: 110
2019-08-21 14:35:04.599 zwm, getAndSet 2: 999
2019-08-21 14:35:04.599 zwm, incrementAndGet 1: 1000
2019-08-21 14:35:04.599 zwm, incrementAndGet 2: 1000
2019-08-21 14:35:04.599 zwm, decrementAndGet 1: 999
2019-08-21 14:35:04.599 zwm, decrementAndGet 2: 999
2019-08-21 14:35:04.599 zwm, addAndGet 1: 1009
2019-08-21 14:35:04.599 zwm, addAndGet 2: 1009
2019-08-21 14:35:04.599 zwm, set: 100
2019-08-21 14:35:04.600 zwm, compareAndSet, result: false
2019-08-21 14:35:04.600 zwm, compareAndSet, result: true
2019-08-21 14:35:04.600 zwm, compareAndSet: 1000
2019-08-21 14:35:04.600 zwm, intValue: 1000

三、原理

重要参数

//获取UnSafe实例(import sun.misc.Unsafe;)
private static final Unsafe unsafe = Unsafe.getUnsafe();

//标识value字段的偏移量
private static final long valueOffset;

//静态代码块
//调用Unsafe的objectFieldOffset()方法获取value字段在类中的偏移量,在后面进行CAS操作时使用
static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}

//用于实际存储数据,用volatile修饰保证可见性
private volatile int value;

构造函数

//无参构造函数
public AtomicInteger() {
}

//指定int型数据的构造函数
public AtomicInteger(int initialValue) {
    value = initialValue;
}

public final int get()

//获取int型数据
public final int get() {
    return value;
}

public final int getAndIncrement()

//先返回旧值,然后加1
public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int getAndDecrement()

//先返回旧值,然后减1
public final int getAndDecrement() {
    return unsafe.getAndAddInt(this, valueOffset, -1);
}

public final int getAndAdd(int delta)

//先返回旧值,然后加指定的值
public final int getAndAdd(int delta) {
    return unsafe.getAndAddInt(this, valueOffset, delta);
}

public final int getAndSet(int newValue)

//先返回旧值,然后设置为指定的值
public final int getAndSet(int newValue) {
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}

public final int incrementAndGet()

//先加1,然后返回新值
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

public final int decrementAndGet()

//先减1,然后返回新值
public final int decrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}

public final int addAndGet(int delta)

//先加指定的值,然后返回新值
public final int addAndGet(int delta) {
    return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}

public final void set(int newValue)

//设置指定的值
public final void set(int newValue) {
    value = newValue;
}

public final boolean compareAndSet(int expect, int update)

//先跟期望的值比较,如果相等则设置成指定的值
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

public int intValue()

//返回int型数据
public int intValue() {
    return get();
}

public long longValue()

//返回long型数据
public long longValue() {
    return (long)get();
}

四、主题

CAS中的ABA问题

CAS并非完美的,它会导致ABA问题。例如当前内存的值一开始是A,被另外一个线程先改为B然后再改为A,那么当前线程访问的时候发现是A,则认为它没有被其他线程访问过。

CAS问题例子:

//测试代码
public void testABA() {
    Log.d(TAG, "zwm, ABA: " + atomicInteger.get());
    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "zwm, run, thread: " + Thread.currentThread().getName());
            atomicInteger.compareAndSet(1000, 1111);
            Log.d(TAG, "zwm, ABA: " + atomicInteger.get());
            atomicInteger.compareAndSet(1111, 1000);
            Log.d(TAG, "zwm, ABA: " + atomicInteger.get());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "zwm, end, thread: " + Thread.currentThread().getName());
        }
    });
    thread.start();

    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    atomicInteger.compareAndSet(1000, 999);
    Log.d(TAG, "zwm, ABA: " + atomicInteger.get());
}

//输出log
2019-08-21 15:21:26.031 zwm, ABA: 1000
2019-08-21 15:21:26.034 zwm, run, thread: Thread-10
2019-08-21 15:21:26.034 zwm, ABA: 1111
2019-08-21 15:21:26.034 zwm, ABA: 1000
2019-08-21 15:21:28.035 zwm, end, thread: Thread-10
2019-08-21 15:21:28.036 zwm, ABA: 999

CAS中的ABA问题的解决方案:AtomicStampedReference

错误使用:

//测试代码
private AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1000, 10);
public void testABAFix() {
    Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference());
    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "zwm, run, thread: " + Thread.currentThread().getName());
            int stamp = atomicStampedReference.getStamp();
            Log.d(TAG, "zwm, stamp: " + stamp);
            boolean result = atomicStampedReference.compareAndSet(1000, 1111, stamp, stamp + 1);
            Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference() + ", result: " + result);
            stamp = atomicStampedReference.getStamp();
            Log.d(TAG, "zwm, stamp: " + stamp);
            atomicStampedReference.compareAndSet(1111, 1000, stamp, stamp + 1);
            Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference() + ", result: " + result);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "zwm, end, thread: " + Thread.currentThread().getName());
        }
    });
    thread.start();

    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    int stamp = atomicStampedReference.getStamp();
    Log.d(TAG, "zwm, stamp: " + stamp);
    boolean result = atomicStampedReference.compareAndSet(1000, 999, stamp, stamp + 1);
    Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference() + ", result: " + result);
}

//输出log
2019-08-21 16:45:21.153 zwm, testMethod
2019-08-21 16:45:21.156 zwm, ABAFix: 1000
2019-08-21 16:45:21.158 zwm, run, thread: Thread-10
2019-08-21 16:45:21.158 zwm, stamp: 10
2019-08-21 16:45:21.159 zwm, ABAFix: 1000, result: false //更新失败
2019-08-21 16:45:21.159 zwm, stamp: 10
2019-08-21 16:45:21.159 zwm, ABAFix: 1000, result: false //更新失败
2019-08-21 16:45:23.162 zwm, end, thread: Thread-10
2019-08-21 16:45:23.163 zwm, stamp: 10
2019-08-21 16:45:23.164 zwm, ABAFix: 1000, result: false //更新失败

//分析
AtomicStampedReference#compareAndSet:
public boolean compareAndSet(V   expectedReference,
                             V   newReference,
                             int expectedStamp,
                             int newStamp) {
    Pair<V> current = pair;
    return
        expectedReference == current.reference && //注意:这里使用==操作符进行比较,比较的是对象的引用,即内存地址是否相同
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
}
==> 例子中传递的expectedReference值为1000,超出了Integer的缓存空间[-128,127],因此会在堆内存中创建新的Integer对象,拥有与current.reference不同的内存地址。

正确使用:

//测试代码
private AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1000, 10);
public void testABAFix() {
    Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference());
    int orginStamp = atomicStampedReference.getStamp();

    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "zwm, run, thread: " + Thread.currentThread().getName());
            int stamp = atomicStampedReference.getStamp();
            Log.d(TAG, "zwm, stamp: " + stamp);
            Integer current = atomicStampedReference.getReference(); //注意这里写法
            boolean result = atomicStampedReference.compareAndSet(current, 1111, stamp, stamp + 1); //注意这里写法
            Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference() + ", result: " + result);
            stamp = atomicStampedReference.getStamp();
            Log.d(TAG, "zwm, stamp: " + stamp);
            current = atomicStampedReference.getReference(); //注意这里写法
            atomicStampedReference.compareAndSet(current, 1000, stamp, stamp + 1); //注意这里写法
            Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference() + ", result: " + result);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "zwm, end, thread: " + Thread.currentThread().getName());
        }
    });
    thread.start();

    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Log.d(TAG, "zwm, orginStamp: " + orginStamp);
    Integer current = atomicStampedReference.getReference();
    boolean result = atomicStampedReference.compareAndSet(current, 9999, orginStamp, orginStamp + 1);
    Log.d(TAG, "zwm, ABAFix: " + atomicStampedReference.getReference() + ", result: " + result);
}

//输出log
2019-08-21 17:07:13.245 zwm, testMethod
2019-08-21 17:07:13.248 zwm, ABAFix: 1000
2019-08-21 17:07:13.251 zwm, run, thread: Thread-10
2019-08-21 17:07:13.251 zwm, stamp: 10
2019-08-21 17:07:13.251 zwm, ABAFix: 1111, result: true //更新成功
2019-08-21 17:07:13.251 zwm, stamp: 11
2019-08-21 17:07:13.251 zwm, ABAFix: 1000, result: true //更新成功
2019-08-21 17:07:15.252 zwm, end, thread: Thread-10
2019-08-21 17:07:15.253 zwm, orginStamp: 10
2019-08-21 17:07:15.253 zwm, ABAFix: 1000, result: false //更新失败
上一篇 下一篇

猜你喜欢

热点阅读