保证Java中的原子操作方式有两种方式
1 加锁(能够理解悲观锁机制)
2 CAS(能够理解为乐观锁机制)
CAS全称是Compare and Swap 即比较并替换。在JDK中许多地方均可以看到它的身影,好比AQS同步组件,Atomic原子类操做等等都是以CAS实现的。其中java.util.concurrent 中的许多概念源自 Doug Lea 的 util.concurrent 库,而Doug lea大神在同步组件中大量使用使用CAS技术鬼斧神工地实现了Java多线程的并发操做。java
在CAS中有三个参数:内存值V、旧的预期值A,要更新的值B。更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改成B。
来看一下Atomic包的源码中是如何使用的CAS,并分析它的原理
AtomicInteger的成员变量多线程
// setup to use Unsafe.compareAndSwapInt for updates 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;
AtomicInteger的成员变量进行说明
1 Unsafe
Java语言不像C,C++那样能够直接访问底层操做系统,可是JVM为咱们提供了一个后门,这个后门就是unsafe。unsafe为咱们提供了硬件级别的原子操做 。
2 valueOffset
至于valueOffset对象,是经过unsafe.objectFieldOffset方法获得,所表明的是AtomicInteger对象value成员变量在内存中的偏移量。咱们能够简单地把valueOffset理解为value变量的内存地址。
3 value
被volatile所修饰被volatile的特色就不在说明了上一篇文章已经提到过了。
AtomicInteger的compareAndSet()并发
/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } //Unsafe.class public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
正是unsafe的compareAndSwapInt方法保证了Compare和Swap操做之间的原子性操做。this
1.ABA问题
由于CAS须要在操做值的时候,检查值有没有发生变化,若是没有发生变化则更新,可是若是一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,可是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类compareAndSet方法的做用是首先检查当前引用是否等于预期引用,而且检查当前标志是否等于预期标志,若是所有相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
2.循环时间长CPU开销大
自旋CAS若是长时间不成功,会给CPU带来很是大的执行开销
3.只能保证一个共享变量的原子操作spa