AtomicLong源码导读

AtomicLong是JDK5开始提供的,它的做用是:对长整型进行原子操做。相似的原子类还有:AtomicBoolean、AtomicInteger等,它们的实现原理都是同样的。html

在原子类出现以前,要想让一个long类型的数值完成自增操做保持原子性,那么只能经过加synchronized或者显式锁,这种解决方式不只会让代码编写更加复杂,并且效率也不高。java

原子类的出现,提供了另外一种解决思路来保证操做的原子性,那就是:CAS,关于CAS的详细说明能够看笔者的另外一篇文章:《关于CAS的一点理解和思考》。缓存

对变量加volatile关键字,保证了有序性和可见性,再经过CAS来保证操做的原子性,最终就能保证数据的并发安全。安全

UML 在这里插入图片描述 AtomicLong的结构仍是很简单的,实现了java.io.Serializable接口,表示它能够被序列化,继承了java.lang.Number,表明它是一个数值,能够转换成其余数值类型,如int、float。markdown

属性

AtomicLong的属性并很少,它依赖于Unsafe类的compareAndSwapLong()方法,只有Unsafe才能够调用底层的CAS操做。 它记录了底层JVM是否支持无锁的方式去更新long类型,double和long这两个类型比较特殊,占用64位空间,具体细节后面能够单独写一篇文章记录下来。 AtomicLong用value表明它的具体数值,被volatile修饰,保证了它的有序性和可见性。并发

// 须要依赖于Unsafe.compareAndSwapLong()来原子的更新value
private static final Unsafe unsafe = Unsafe.getUnsafe();
// value属性相较于AtomicLong的内存地址偏移量,CAS操做时须要用到
private static final long valueOffset;

/* 记录底层JVM是否支持无锁的方式去更新long类型。 由于long和其余数值有点不同,它占用8字节,须要占用两个32位的空间,存在写高低位的问题。 */
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

/* 记录底层JVM是否支持无锁的方式去更新long类型,并把它缓存在VM_SUPPORTS_LONG_CAS中。 */
private static native boolean VMSupportsCS8();

// 结果值,volatile保证了它的有序性和可见性。
private volatile long value;
复制代码

构造函数

AtomicLong提供了两个构造函数,默认的value值为0,你也能够手动指定一个初始值。app

// 手动指定一个初始值
public AtomicLong(long initialValue) {
	value = initialValue;
}

// 使用long的默认值0
public AtomicLong() {
}
复制代码

核心操做

add

AtomicLong提供了两个add方法:addAndGetgetAndAddide

addAndGet() 先添加再获取:函数

/* 以原子的方式加上给定值,再返回 */
public final long addAndGet(long delta) {
	return unsafe.getAndAddLong(this, valueOffset, delta) + delta;
}
复制代码

getAndAdd() 先添加再获取:oop

/* 以原子的方式加上给定值,返回操做前的结果 */
public final long getAndAdd(long delta) {
	return unsafe.getAndAddLong(this, valueOffset, delta);
}
复制代码

两个方法的目的都是将value加上给定的值,无非就是一个返回操做前的值,一个返回操做后的值。

它们调用的方法都是unsafe.getAndAddLong()方法,这才是核心:

/* 以原子的方式,加上给定值,并返回旧值。 var1:对象实例 var2:value相较于类的内存地址偏移量 var4:加上给定值 */
public final long getAndAddLong(Object var1, long var2, long var4) {
    long var6;
    do {
    	// 从主存中,读取最新值
        var6 = this.getLongVolatile(var1, var2);
        // CAS的方式将值从var6修改成(var6 + var4),若是失败就循环重试,直到成功为止。
    } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
	// 返回旧值
    return var6;
}
复制代码

实现思路是:从主存中读取变量最新的值,经过CAS的方式尝试去修改,若是修改失败,则说明变量期间已经被其余线程改过了,当前线程会循环重试,直到成功为止。

increment

递增操做,和add同样,只是add的值为1。也提供了两个方法:getAndIncrementincrementAndGet,做用都是值递增,一个返回旧值,一个返回新值。

/* 以原子的方式,将value递增,返回旧值。 */
public final long getAndIncrement() {
	// 和add()同样,递增就是+1
	return unsafe.getAndAddLong(this, valueOffset, 1L);
}

/* 以原子的方式,将value递增,返回新值。 */
public final long incrementAndGet() {
	return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}
复制代码

decrement

递减操做,依然和add同样,只是add的值为-1。也提供了两个方法:getAndDecrementdecrementAndGet,做用都是值递减,一个返回旧值,一个返回新值。

/** 以原子的方式,将value递减,返回旧值。 */
public final long getAndDecrement() {
	// 和add()同样,递增就是-1
	return unsafe.getAndAddLong(this, valueOffset, -1L);
}

/** 以原子的方式,将value递减,返回新值。 */
public final long decrementAndGet() {
	return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
}
复制代码

compareAndSet

比较并设置,以原子的方式,将当前值从expect修改成update,成功返回true,失败返回false,和CAS一个道理。

/** 以原子的方式,将当前值从expect改成update expect:预期的旧值 update:要修改的新值 */
public final boolean compareAndSet(long expect, long update) {
	return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
复制代码

仍是依赖于unsafe实现的,unsafe.compareAndSwapLong()就是去调用底层的CAS操做,native方法,使用C编写,须要调用系统函数。

weakCompareAndSet

不多会用到这个方法,并且在JDK8中,它和compareAndSet代码如出一辙,没有任何区别,直到JDK9才被实现。 它的做用是:操做只保留volatile自身的特性,去除happens-before规则带来的内存语义,即没法保证没有别volatile修饰的其余变量的有序性和可见性。

/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * <p><a href="package-summary.html#weakCompareAndSet">May fail * spuriously and does not provide ordering guarantees</a>, so is * only rarely an appropriate alternative to {@code compareAndSet}. * * @param expect the expected value * @param update the new value * @return {@code true} if successful */
// JDK8中,和compareAndSet如出一辙
public final boolean weakCompareAndSet(long expect, long update) {
	return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
复制代码

总结

原子类的代码并不复杂,逻辑都很简单,就是经过volatile+CAS的方式来保证数据的并发安全。 数值的更新几乎都是依赖于Unsafe类去完成的,CAS操做自己Java代码不能实现,须要调用本地方法,经过C去调用系统函数。同时CAS自己依赖于现代CPU支持的并发原语,即CPU会保证比较并交换这个过程自己不会被打断。

相关文章
相关标签/搜索