前言
本文主要分析一下原子更新基本类型包括
AtomicBoolean
,AtomicInteger
和AtomicLong
. 由于这三个类的基本操作和原理是一样的,因此主要分析一下AtomicInteger
类就可以了.
本文源代码: 代码下载
原子更新基本类型类 AtomicInteger
例子1
package com.sourcecode.atomic_AtomicInteger;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
public class AtomicIntegerTest {
static AtomicInteger ai = new AtomicInteger(1);
public static void main(String[] args) {
System.out.println(ai.getAndIncrement()); // 1
System.out.println(ai.get()); // 2
// Since 1.8
IntBinaryOperator accumulatorFunction = (x, y) -> x + y;
System.out.println(ai.accumulateAndGet(10, accumulatorFunction)); // 12
IntUnaryOperator updateFunction = x -> x * x;
System.out.println(ai.updateAndGet(updateFunction)); // 144
}
}
上面的操作都是原子操作,
accumulateAndGet
和updateAndGet
是针对Function
所做的一些操作.
源码
AtomicInteger
的实现主要依赖于Unsafe
类的CAS
操作,更新一下value
的值.value
用volatile
修饰. 关于Unsafe
可以参考[并发J.U.C]---简单理解Unsafe , 关于```volatile``留作后续单独分析.
// setup to use Unsafe.compareAndSwapInt for updates
//private static final Unsafe unsafe = Unsafe.getUnsafe(); 官方源码
private static Unsafe unsafe = null; // 为了自己获得unsafe
private static final long valueOffset;
static {
try {
/**
* 自己通过反射获得unsafe
*/
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe)f.get(null);
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// 设置为volatile属性
private volatile int value;
/**
* 原子的方式设置旧的值加1
* 返回旧的值
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int get() {
return value;
}
/**
* for循环操作设置新值为
* 应用于accumulatorFunction后的值
* 返回新的值
*/
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
/**
* for循环操作设置新值为
* 应用于updateFunction后的值
* 返回新的值
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
关于
lazySet(int newValue)
可以参考 AtomicLong.lazySet是如何工作的?
简单提一下,
AtomicBoolean
中的value
也是个int
类型的,只是用value==1
表示true
,而value==0
表示false
.AtomicLong
基本上与AtomicInteger
实现一样.
原子更新引用类型 AtomicReference
原子更新基本类型的
AtomicInteger
,只能更新一个变量,如果要原子更新多个变量,就需要使用这个原子更新引用类型提供的类.
例子2
public class AtomicReferenceTest {
public static AtomicReference atomicUserRef = new AtomicReference();
public static void main(String[] args) {
User user = new User("conan", 15);
atomicUserRef.set(user); // 非原子类操作
User updateUser = new User("Shinichi", 17);
atomicUserRef.compareAndSet(user, updateUser); // 原子类操作
System.out.println(atomicUserRef.get().getName());
System.out.println(atomicUserRef.get().getOld());
}
static class User {
private String name;
private int old;
public User(String name, int old) {
this.name = name;
this.old = old;
}
public String getName() {
return name;
}
public int getOld() {
return old;
}
}
}
结果如下: 通过设置引用
user
可以看到AtomicReference
中存的user
发生了变化.
Shinichi
17
源码简单分析
接下来看看该类的几个函数
set
,compareAndSet
,get
.
private volatile V value;
public AtomicReference(V initialValue) {
value = initialValue;
}
public AtomicReference() {
}
可以看到
value
类型在AtomicInteger
是int
类型,而在AtomicReference
中是泛型(这个也是它们之间最大的不同点),当然从AtomicInteger
也可以知道AtomicReference
的各种操作也是通过unsafe
完成的.
// 返回value
public final V get() {
return value;
}
// 非原子类操作 设置value
public final void set(V newValue) {
value = newValue;
}
// 原子操作 设置新value
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
原子更新数组 AtomicIntegerArray
通过原子的方式更新数组里的某个元素
例子3
public class AtomicIntegerArrayTest {
static int[] value = new int[] { 1, 2, 3, 4, 5};
static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(value);
public static void main(String[] args) {
for (int i = 0; i < value.length; i++) {
atomicIntegerArray.compareAndSet(i, value[i], -1);
}
System.out.print("new value:");
for (int i = 0; i < value.length; i++) {
System.out.print(atomicIntegerArray.get(i) + ",");
}
System.out.print("\norigin array:");
for (int i = 0; i < value.length; i++) {
System.out.print(value[i] + ",");
}
}
}
结果如下: 可以看到虽然
AtomicIntegerArray
中取到的值是发生了改变,但是原数组里面的数值却没有发生任何改变.原因在于,AtomicIntegerArray
里面在构造函数部分就已经copy
了一个一模一样的数组进行操作,所以AtomicIntegerArray
中针对数组的操作不会对原来的数组有影响.
new value:-1,-1,-1,-1,-1,
origin array:1,2,3,4,5,
简单分析源码
可以看到如下的构造函数中内部
private static int base;
private static final int shift;
private final int[] array;
public AtomicIntegerArray(int length) {
array = new int[length];
}
public AtomicIntegerArray(int[] array) {
// Visibility guaranteed by final field guarantees
this.array = array.clone();
//System.out.println("this.array:" + this.array);
//System.out.println("origin array:" + array);
}
set 函数
public final boolean compareAndSet(int i, int expect, int update) {
return compareAndSetRaw(checkedByteOffset(i), expect, update);
}
private boolean compareAndSetRaw(long offset, int expect, int update) {
return unsafe.compareAndSwapInt(array, offset, expect, update);
}
// 计算出对应下标的offset
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << shift) + base;
}
get 函数
public final int get(int i) {
return getRaw(checkedByteOffset(i));
}
public final int get(int i) {
return getRaw(checkedByteOffset(i));
}
private int getRaw(long offset) {
return unsafe.getIntVolatile(array, offset);
}
另外两个类(
AtomicLongArray
和AtomicReferenceArray
(用于自定义类型))的原理几乎一样.
原子更新字段类 AtomicIntegerFieldUpdater
如果需原子地更新某个类里的某个字段时,就需要使用原子更新字段类. 包括
AtomicIntegerFieldUpdater
,AtomicLongFieldUpdater
,AtomicStampedReference
和AtomicReferenceFieldUpdater
. 以AtomicIntegerFieldUpdater
为例,其余的原理差不多,AtomicReferenceFieldUpdater
会放到另外一篇博客分析.
例子4
此片段来自
Java 并发编程的艺术
要想原子地更新字段类需要两步。第一步,因为原子更新字段类都是抽象类,每次使用的
时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第
二步,更新类的字段(属性)必须使用public volatile修饰符。
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterTest {
private static AtomicIntegerFieldUpdater a = AtomicIntegerFieldUpdater.
newUpdater(User.class, "old");
public static void main(String[] args) {
User conan = new User("test", 10);
System.out.println(a.getAndIncrement(conan));
System.out.println(a.get(conan));
}
public static class User {
private String name;
public volatile int old;
public User(String name, int old) {
this.name = name;
this.old = old;
}
public String getName() {
return name;
}
public int getOld() {
return old;
}
}
}