【详解】Java并发之AtomicxxxFieldUpdater
引出
由于原子性的类型是后期引出的,但是想让原来已经写好的属性也具有原子性,就可以利用这个类
AtomicXXXFieldUpdater主要包括以下几个:AtomicIntegerFieldUpdater
,AtomicLongFieldUpdater
,AtomicReferenceFieldUpdater
。
要求
- 字段必须是volatile类型的,在线程之间共享变量时保证立即可见
- 字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。
- 对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
- 只能是实例变量,不能是类变量,也就是说不能加static关键字。
- 只能是可修改变量,不能使final变量,因为final的语义就是不可修改。
- 对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater
举例使用
public class AtomicXXXFieldUpdater {
public static void main(String[] args) throws InterruptedException {
TestMe testMe = new TestMe();
Set<Integer> data = new HashSet<>();
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 500; j++) {
testMe.updateNum();
}
});
thread.start();
thread.join();
}
System.out.println(data.size());
}
}
class TestMe {
private volatile int num = 0;
public void updateNum(){
AtomicIntegerFieldUpdater updaterNum = AtomicIntegerFieldUpdater.newUpdater(getClass(),"num");
int i = updaterNum.incrementAndGet(this);
System.out.println(i);
}
}
使用场景总结
1. 想让其他的类的属性具备原子性
2. 不想使用任何锁
3.大量需要原子类型修饰的对象,相比较会消耗内存
- 如果直接使用原子类型修饰,需要包装所有的数据
- 但是通过Updater更新,只需要每次更新其中一个数据