java 从jdk 1.5 开始提供了 java.util.concurrent.atomic包,这个包中原子操作类
提供了一种用法简单,性能高效,线程安全地更新一个变量的方式。
因为变量有很多种,所以在automic包中提供了13类,属于4种类型的原子更新方式“
1.原子更新基本类型类
AtomicBoolean :原子更新布尔类型
AtomicInteger:原子更新整形
AtomicLong:原子更新长整型
以上三个类方法几乎一摸一样,所以学习一个就能知道其它的怎么调用了,这里以 AtomicInteger 进行解释
public final int addAndGet(int delta). 以原子的方式将输入的数值与实例中值(AtomicInteger 中的Value)相加并返回结果。
public final boolean compareAndSet(int expect, int update) ,如果输入的数值等于预期值,则以原子的方式将该值设置为输入值
public final int getAndIncrement() 以原子的方式将当前值加 1.注意返回的是自增前的值
public final void lazySet(int newValue) 。最终会设置成newValue,使用lazySet 设置值后,可能会导致其他线程在之后一小段时间内还是可以读到旧
的值。
public final int getAndSet(int newValue) :以原子的方式设置为newValue的值,并返回旧值
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerTest {
static AtomicInteger atomicInteger = new AtomicInteger(1);
public static void main(String[] args) {
System.out.println(atomicInteger.getAndIncrement());
System.out.println(atomicInteger.get());
}
}
输出结果如下:
1
2
Process finished with exit code 0
那么getAndInsrement 是如何实现原子操作的呢?
在jdk1.7中,AtomicInteger的getAndIncrement是这样的:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
而在jdk1.8中,是这样的:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
本文使用jdk 1.7 进行分析
源码中for 循环体的第一步先取得,AtomicInteger里的数值,第二步对AtomicInteger 的当前数值进行加 1 操作,关键第三步
compareAndSet(current, next)方法来进行原子更新操作,该方法检查当前数值是否等于current,等于意味着Atomicinteger的值没有被其他线程修改过
则将AtomicInteger的当前数值更新成next的值,如果不等compareAndSet方法会返回false,程序会进入for循环,重新进行compareAndSet操作。
Atomic包提供了3种基本类型的原子类型,但是java的基本类型里还有char,float和double等。那么问题来了,如何原子的更新其他的基本类型呢,atomic包
里的类基本都是使用unsafe实现的。
unsafe源码
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset, Object expected, Object x);
public final native boolean compareAndSwapLong(Object o, long offset, Object expected, Object x);
通过代码发现unsafe提供三种 CAS 方法,看源码它先是把Boolean 转换成整型,在使用compareAndASwapInt() 进行CAS,所以原子更新char,float,double 变量
也可以采用类似的思路实现
引用自 java 并发编程艺术