1.自定义AtomicInteger
通过自定义AtomicInteger可以帮助我们理解其源码
首先,我们想达到的目的是能够完成一个保证在不使用synchronized关键字的情况下,保证对int的操作安全;
- 首先,策略上不同于synchronized悲观锁的思想,使用乐观锁的思想来保证我们对int的操作安全;
- 得先封装一个int类型的值来作为操作对象,为保证可见性用volatile修饰;
- 采用乐观锁的思想,我们先获取操作对象的值,我们可以使用不断进行cas操作重试的机制知道能够修改成我们的期望值;
大致代码思路如下:
void add(int num) {
while(true) {
//先过去当前操作数的值
int value = getValue();
//我们期望修改后的值
int expect = value + num;
// cas操作来修改从 value 修改成 expect ,成功就结束,不成功while true不断重试
if(cas操作成功)break;
}
}
根据上述思路编写大致代码如下:
/**
* @Description 自定义AtomicInteger类
**/
class CustomAtomicInteger {
private volatile int value;
private static Unsafe unsafe;
//存储字段在CustomAtomicInteger对象中偏移量
private static long valueOffSet;
static {
try {
//使用反射的方式从Unsafe方法中获取到theUnsafe对象来完成后续cas操作
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
valueOffSet = unsafe.objectFieldOffset(CustomAtomicInteger.class.getDeclaredField("value"));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
new RuntimeException(e.getMessage());
}
}
public CustomAtomicInteger(int value) {
this.value = value;
}
public int get() {
return this.value;
}
public void add(int i) {
while (true) {
int prev = this.value;
int next = prev + i;
if (unsafe.compareAndSwapInt(this, valueOffSet, prev, next)) {
break;
}
}
}
}
编写测试代码
public class MyAtomicIntegerTest {
static CustomAtomicInteger customAtomicInteger = new CustomAtomicInteger(0);
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
for (int i1 = 0; i1 < 10; i1++) {
new Thread(() -> {
for (int i2 = 0; i2 < 10000; i2++) {
customAtomicInteger.add(1);
}
}).start();
}
Thread.sleep(1000);
System.out.println(customAtomicInteger.get());
//AtomicInteger
}
}
可以观察到测试结果正常;
2.AtomicInteger源码分析
主要观察部分
先观察AtomicInteger的结构,红框部分是此次分析主要部分;
可以观察到,同样AtomicInteger对int的操作同样是用volitile封装的,保证可见性;同时也用valueOffset存储了在对象中int属性的偏移量;
incrementAndGet方法源码分析
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
/**分析:getAndAddInt方法的第一次var1对当前AtomicInteger类型的对象
* var2 是value属性的在对象中的偏移量,方便cas操作时进行修改;
* var5 即为此时内存中value属性的值
* 然后进行cas操作 从 var5 -> var5 + var4 成功才结束循环
*/
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
从源码分析注释可以看出,其中使用乐观锁和cas组合能完成对int类型的原子操作;和我们在上方自定义AtomicInteger的思想是类似的;