本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。
原子类型字段更新器
在java.util.concurrent.atomic
中,原子类型字段更新器有以下三种:
- AtomicIntegerFieldUpdater:基于反射的工具类,可以原子性的更新指定对象的指定int类型字段。
- AtomicLongFieldUpdater:基于反射的工具类,可以原子性的更新指定对象的指定long类型字段。
- AtomicReferenceFieldUpdater:基于反射的工具类,可以原子性的更新指定对象的指定应用类型字段。
使用规则
原子类型字段更新器在内部通过Unsafe类的native方法保证操作的原子性。
关于原子类型字段更新器的使用需要注意以下几个方面:
- 字段必须是volatile类型的,用于保证可见性。
- 字段和字段更新器的访问类型(public/protected/private)必须一致。
- 字段只能是实例变量,不能是类变量(static)。
- 字段不能是final的变量,这样的字段不可修改。
- 如果要处理Integer和Long类型,则需要使用AtomicReferenceFieldUpdater
使用列子(以AtomicIntegerFieldUpdater为列)
public class AtomicIntegerFieldUpdaterTest {
private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
public static void main(String[] args) {
// 设置柯南的年龄是10岁
User conan = new User("conan",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;
}
}
}
方法说明
首先学习上述三种原子类型字段更新器的通用方法,这些方法如下:
- 构造器:只有一个无参protected的构造函数,并不可用。
- newUpdater(fieldClass,fieldName):原子类型字段更新器提供的一个静态泛型方法,用于创建和返回指定字段和指定类型的原子类型字段更新器实例对象。
- get(obj):赋值,具有原子性和可见性。
- set(obj):取值,具有原子性和可见性。
- lazySet(obj,newValue):赋值,具有原子性,不具备可见性。
- getAndSet(obj,newValue):赋值并返回旧值,具有原子性和可见性。
- compareAndSet(obj,expect,update):如果当前是期望值则赋值并返回赋值成功与否,具有原子性和可见性。
- weakCompareAndSet(obj,expect,update):与compareAndSet(obj,expect,update)类似。
原子类型字段更新器的通用方法与普通原子类型的通用方法类似,唯一的区别在于多了一个参数:obj(被修改的字段的所属对象)。
AtomicIntegerFieldUpdater和AtomicLongFieldUpdater的独有方法,下面这些方法AtomicReferenceFieldUpdater类没有:
- getAndAdd(obj):增量计算并返回旧值,具有原子性和可见性。
- addAndGet(obj):增量计算并返回新值,具有原子性和可见性。
- getAndIncrement(obj):自增并返回旧值,类似i ++,具有原子性和可见性。
- incrementAndGet(obj):自增并返回新值,类似++ i,具有原子性和可见性。
- getAndDecrement(obj):自减并返回旧值,类似i --,具有原子性和可见性。
- decrementAndGet(obj):自减并返回新值,类似-- i,具有原子性和可见性。