AtomicInteger
AtomicInteger 是一个支持原子操作的 Integer 类,
保证对AtomicInteger类型变量的增加和减少操作是原子性
- 继承自Number,实现Serializable接口
源码:
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); }
}
private volatile int value;
- value是用来存储整数的时间变量,使用volatile关键字
valueOffset是用来记录value本身在内存的编译地址的
unsafe是java提供的获得对对象内存地址访问的类
Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。static 代码块获取value字段的偏移量,这个偏移量类似于C语言中的指针值
自增返回新值incrementAndGet
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
自增返回旧值getAndIncrement
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
还有getAndDecrement、decrementAndGet
自增操作调用Unsafe类的getAndAddInt函数
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;
}
参考此处文章
http://ifeve.com/enhanced-cas-in-jdk8/
Unsafe是经过特殊处理的,不能理解成常规的java代码,区别在于:
在调用getAndAddInt的时候,如果系统底层支持fetch-and-add,那么它执行的就是native方法,使用的是fetch-and-add;
如果不支持,就按照上面的所看到的getAndAddInt方法体那样,以java代码的方式去执行,使用的是compare-and-swap;
CAS 比较并交换
- CAS操作经常被用来实现无锁数据结构
- 将内存值与预期值进行比较,如果相等才将新值替换到内存中,并返回true
- 如果不相等,则直接返回false表示操作失败。
compareAndSwapInt()方法的声明如下,是一个native方法
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
该方法调用C++层JVM的源码。
CAS操作的ABA问题
CAS操作只有内存值与预期值相等才会更新内存中的值
CAS操作可能会出现这种现象:原来内存值为A,线程1和线程2都获取该值,
然后线程1使用CAS将内存值修改为B,然后又使用CAS将内存值修改回A;这时线程2使用CAS对内存值进行修改时发现内存值仍然是A,然后线程2修改成功。这种现象是“ABA问题”,也称“调包问题”。
链式数据结构可能会无故删除节点
Java中被无故删除的节点会被垃圾回收机制回收
但在C/C++中这就造成内存泄漏