一、概念
类定义:
public class AtomicInteger extends Number implements java.io.Serializable
- 继承了Number抽象类,说明是个数字类型。
- 实现了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 //更新失败
网友评论