目录
Java从JDK1.5开始提供了J.U.C下的atomic包,atomic包提供了一系列的操作简单,性能高效,并能保证线程安全的类去更新基本类型变量,数组元素,引用类型以及更新对象中的字段类型。
atomic包里的类基本都是使用 Unsafe 实现的包装类,使用Unsafe提供的三个CAS方法结合死循环实现的,也就是乐观锁。
我们Java中的基本数据类型是用的非常多的,Atomic包针对基本数据类型提供了3个类,使用原子的方式更新基本类型。
以上3个类提供的方法几乎一模一样,所以这里只以AtomicInteger为例进行讲解。
getAndIncrement() 是如何实现原子操作的呢?让我们一起分析其实现原理。
可以看出,该方法实际上是调用了unsafe实例的getAndAddInt方法,unsafe实例的获取时通过UnSafe类的静态方法getUnsafe获取:
Unsafe 是JDK提供的一个工具类,里面有很多 native 方法,即本地方法,是 JVM 使用 C 帮我们实现的,我们只要记住他提供了一些安全的操作方法,是直接操作内存的。
unsafe.getAndAddInt(this,valueOffset,1) 方法中的三个参数:
我们接着往里看:
这里使用了 do-while 循环,其实也就是乐观锁,非阻塞的同步方式,一直尝试进行原子操作更新,直到成功。
Atomic包提供了3种基本类型的原子更新,但是Java的基本类型里还有 char、float和double等。那么问题来了,如何原子的更新其他的基本类型呢?Atomic包里的类基本都是使用Unsafe实现的,让我们一起看一下Unsafe的源码。
/**
* 如果当前数值是expected,则原子的将Java变量更新成x
* @return 如果更新成功则返回true
*/
public final native boolean compareAndSwapObject(Object o,long offset , Object expected , Object x );
public final native boolean compareAndSwapInt(Object o , long offset , int expected, int x );
public final native boolean compareAndSwapLong(Object o , long offset , long expected ,long x );
通过代码,我们发现Unsafe只提供了三种CAS方法:
再看?AtomicBoolean 源码
它是先把Boolean转换成整型,再使用 compareAndSwapInt 进行CAS,所以原子更新char、float和double变量也可以用类似的思路来实现。
通过原子的方式更新数组里的某个元素,即操作数组元素是线程安全的,Atomic包提供了以下3个类:
上述几个类提供的方法几乎一样,我们以AtomicIntegerArray类为例讲解,其常用方法如下:
上面我们学会了如何原子更新基本类型,但是我们平常使用最多的还是引用类型,这个要如何更新呢?Atomic包提供了以下3个类:
以上几个类提供的方法几乎一样,所以此处我们仅以AtomicReference为例进行讲解,AtomicReference的使用示例代码如下:
其实现原理是依靠了 unsafe.compareAndSwapObject 方法。
如果需原子地更新某个类里的某个字段时,就需要使用原子更新字段类,Atomic包提供了以下3个类进行原子字段更新。
要想原子地更新字段类需要两步:
以上3个类提供的方法几乎一样,此处仅以 AtomicIntegerFieldUpdater 为例进行讲解,AtomicIntegerFieldUpdater的 示例代码如下: