CAS
看过了前几章大家可能都有这么个问题,总是再说CAS,那么CAS到底是个什么东西?
CAS即compareAndSwap,比较并交换。在我们使用CAS修改某一个数据时,有点像你们常用的数据库乐观锁策略,在更新前将时间戳比较,若时间戳匹配则允许更新,否则不允许。但是注意,在计算机的CAS中,由我们的Unsafe的native方法执行CAS指令。
- 先看一下它的参数
这里需要4个参数,执行CAS时,会去指定的对象(var1)的内存地址块(var2)先比较当前内存中的值与预期值(var4)是否一致,一致则将当前值更改为更新值(var5)。/* var1:需要更新的对象 var2:要更新的内存地址 var4:期望值 var5:更新值 */ public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
注意这里与我们常说的数据库乐观锁机制是有小小的区别的:- 数据库的时间戳或是版本号是递增的,可以确保不会重复,但是内存中的值却可能是任意值,这时就可能存在
ABA
的问题。
- 数据库的时间戳或是版本号是递增的,可以确保不会重复,但是内存中的值却可能是任意值,这时就可能存在
这个源码就不做分析了。
Unsafe
unsafe类就是Java中CAS操作的执行类,简单说说这个类。
unsafe可以:
- 裸内存的申请/释放/访问(你现在可以在Java中直接操作内存了);
- 实现对低层硬件的atomic/volatile支持;
- 直接对线程管理(包括阻塞,唤醒等等)
- 增加内存屏障
- 创建未初始化对象(现在你可以
跳过对象的构造函数
来初始化对象了,比反射还牛) - 执行CAS操作
Java官方并不建议用户直接使用这个类
,因为它太过于底层,并且看名字就知道这个用多了可能有线程安全问题,所以你并不能直接new出Unsafe对象。
但是你实在想要在Java里面写c的话,还是有方法的:
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
接下来你就可以体验一把在Java中写c的感觉了。。。
别的就不介绍了,这个类过于底层切存在安全性问题,不推荐使用
atomic
看完上面的CAS和Unsafe再看我们的atomic就非常简单了。
就拿AtomicInteger来看:
- 选个incrementAndGet方法来看把:
其实atomic系的类内部更新操作都是使用的Unsafe提供的CAS方法,while循环直到更新成功位置,没啥好讲的。这里提一下,这个使用CAS机制实现数据更新,在高并发情况下可能会多次失败。public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } 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; }