jdk1.5开始提供java.util.concurrent.atomic包下的原子操作类,基本采用的是unsafe实现的包装类
Atomic 包里一共提供了 13 个类,属于 4 种类型的原子更新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性(字段)。
原子更新基本类型
- AtomicBoolean //原子更新布尔类型
- AtomicInteger //原子更新整型
- AtomicLong //原子更新长整型
AtomicInteger 中的常用方法
⚫int addAndGet(int delta):以原子方式将输入的数值与实例中的值
(AtomicInteger 里的 value)相加,并返回结果。
⚫boolean compareAndSet(int expect,int update):如果输入的数值等于预期值,
则以原子方式将该值设置为输入的值。
⚫ int getAndIncrement():以原子方式将当前值加 1,注意,这里返回的是自增前的
值。采用的是CAS算法
public final int getAndIncrement() {
for (; ; ) {
int current = get();// get方法采用的是native getIntVolatile(),保证元素值的可见性
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);
}
jdk 1.8采用的是getAndAddInt方法
public final int getAndAddInt(Object var1, long valueOffset, int var4) {
int var5;
do {
var5 = unsafe.getIntVolatile(var1, valueOffset);
} while(!unsafe.compareAndSwapInt(var1, valueOffset, var5, var5 + var4));
return var5;
}
原子更新数组
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray // 原子更新引用类型数组里的元素。
AtomicIntegerArray中常用的方法有
⚫int addAndGet(int i,int delta):以原子方式将输入值与数组中索引 i 的元素相加。
⚫boolean compareAndSet(int i,int expect,int update):如果当前值等于预期值,则以原子方式将数组位置 i 的元素设置成 update 值。
public static void main(String[] args) {
int a[] = new int[]{1,2};
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(a);
atomicIntegerArray.getAndSet(0,3);
System.out.println(atomicIntegerArray.get(0));
System.out.println(a[0]);
}
输出结果为:
3
1
AtomicIntegerArray 构建是建立在普通数组之上,重新复制新的数组,不改变原来普通数组的值
原子更新引用类型
- AtomicReference
- AtomicReferenceFieldUpdater // 原子更新引用类型里的字段
- AtomicMarkableReference // 原子更新带有标记位的引用类型
AtomicReference为例:
public class AtomicReferenceTest {
public static AtomicReference<User> atomicReference = new AtomicReference<>();
public static void main(String[] args) {
User xiaozhang = new User("xiaozhang", 5);
atomicReference.set(xiaozhang);
atomicReference.compareAndSet(xiaozhang,new User("zhangsan",8));
System.out.println(atomicReference.get().getName());
System.out.println(atomicReference.get().getAge());
}
static class User{
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
}
输出结果:
zhangsan
8
原子更新字段类
- AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
- AtomicLongFieldUpdater:原子更新长整型字段的更新器。
- AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
AstomicIntegerFieldUpdater为例:
第一步:使用静态方法newUpdater()创建一个更新器,并设置想要更新的类和属性
第二步:更新类的字段必须使用public volatile修饰
public class AtomicReferenceTest {
public static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class,"age");
public static void main(String[] args) {
User xiaozhang = new User("xiaozhang", 5);
// 实现年龄+1
a.getAndIncrement(xiaozhang);
System.out.println(a.get(xiaozhang));
}
static class User{
private String name;
// 此处要声明为 public volatile
public volatile int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
}