Java多线程:AtomicIntegerFieldUpdater 原子更新字段类,Java多线程系列--“JUC原子类”05之 AtomicLongFieldUpdater原子类

AtomicIntegerFieldUpdater 

前面我们所讲的几个原子更新引用类型如:AtomicReference,用于整个对象的更新。但不是每次都必须更新整个对象,有可能我们只需对对象中的某个字段进行原子性修改时,那么就需要使用原子更新字段类,Atomic包提供了以下三个类:

  • AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器。
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用CAS进行原子更新时,可能出现的ABA问题。

这几个类基本类似,我们以 AtomicIntegerFieldUpdater 作为例子详细介绍。

不同于以往的几个原子更新类,对于 AtomicIntegerFieldUpdater 的使用稍微有一些限制和约束,约束如下:

1. 字段必须是 volatile 类型的,在线程之间共享变量时保证立即可见。

2. 字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。

3. 只能是实例变量,不能是类变量,也就是说不能加static关键字。

4. 只能是可修改变量,不能是final变量,因为final的语句就是不可修改。实际上final的语义与volatile是有冲突的,两个关键字不能同时存在

5. 对于 AtomicIntegerFieldUpdate 和 AtomicLongFieldUpdate 只能修改 int/long 类型的字段,不能修改包装类型。如果要修改包装类型就需要使用 AtomicReferenceFieldUpdate。

 

我们先来看 AtomicIntegerFieldUpdate 的方法列表

// 受保护的无操作构造方法,供子类使用。
protected AtomicIntFieldUpdater()

// 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。
int addAndGet(T obj, int delta)
// 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。
abstract boolean compareAndSet(T obj, int expect, int update)
// 以原子方式将此更新器管理的给定对象字段当前值减 1。
int decrementAndGet(T obj)
// 获取此更新器管理的在给定对象的字段中保持的当前值。
abstract int get(T obj)
// 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。
int getAndAdd(T obj, int delta)
// 以原子方式将此更新器管理的给定对象字段当前值减 1。
int getAndDecrement(T obj)
// 以原子方式将此更新器管理的给定对象字段的当前值加 1。
int getAndIncrement(T obj)
// 将此更新器管理的给定对象的字段以原子方式设置为给定值,并返回旧值。
int getAndSet(T obj, int newValue)
// 以原子方式将此更新器管理的给定对象字段当前值加 1。
int incrementAndGet(T obj)
// 最后将此更新器管理的给定对象的字段设置为给定更新值。
abstract void lazySet(T obj, int newValue)
// 为对象创建并返回一个具有给定字段的更新器。
static <U> AtomicIntFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName)
// 将此更新器管理的给定对象的字段设置为给定更新值。
abstract void set(T obj, int newValue)
// 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。
abstract boolean weakCompareAndSet(T obj, int expect, int update)

 

要想原子地更新字段类需要两步。第一步,因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第二步,更新类的字段(属性)必须使用public volatile修饰符。

 1 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 2 
 3 public class Demo {
 4     // 新建AtomicIntegerFieldUpdater对象,需要指明是哪个类中的哪个字段
 5     private static AtomicIntegerFieldUpdater<User> atom = AtomicIntegerFieldUpdater.newUpdater(User.class, "id");
 6 
 7     public static void main(String[] args) {
 8         User user = new User(100, 100);
 9         System.out.println("调用atom.addAndGet(user, 50)方法返回值为:" + atom.addAndGet(user, 50));
10         System.out.println("调用后值变为:" + user);
11 
12         System.out.println("调用getAndDecrement(user)方法返回值为:" + atom.getAndDecrement(user));
13         System.out.println("调用后值变为:" + user);
14 
15         System.out.println("调用compareAndSet(user, 149, 200)方法返回值为:" + atom.compareAndSet(user, 149, 200));
16         System.out.println("调用后值变为:" + user);
17     }
18 }
19 
20 class User {
21     volatile int id;
22     volatile int age;
23     public User(int id, int age) {
24         this.id = id;
25         this.age = age;
26     }
27     
28     public String toString() {
29         return "id:" + id + " " + "age:" + age;
30     }
31 }

打印结果为:

调用atom.addAndGet(user, 50)方法返回值为:150
调用后值变为:id:150 age:100
调用getAndDecrement(user)方法返回值为:150
调用后值变为:id:149 age:100
调用compareAndSet(user, 149, 200)方法返回值为:true
调用后值变为:id:200 age:100

 

那么 AtomicIntegerFieldUpdater 是如何进行原子性操作的呢?我们去源码一探究竟

先看newUpdater()的源码如下

1 public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
2     Class<?> caller = Reflection.getCallerClass();
3     if (AtomicInteger.VM_SUPPORTS_LONG_CAS)
4         return new CASUpdater<U>(tclass, fieldName, caller);
5     else
6         return new LockedUpdater<U>(tclass, fieldName, caller);
7 }

说明:newUpdater()的作用是获取一个AtomicIntegerFieldUpdater类型的对象。
它实际上返回的是CASUpdater对象,或者LockedUpdater对象;具体返回哪一个类取决于JVM是否支持int类型的CAS函数。CASUpdater和LockedUpdater都是AtomicIntegerFieldUpdater的子类,它们的实现类似。下面以CASUpdater来进行说明。

CASUpdater类的源码如下:

1 public boolean compareAndSet(T obj, int expect, int update) {
2     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
3     return unsafe.compareAndSwapInt(obj, offset, expect, update);
4 }

说明:它实际上是通过CAS函数操作。如果类的int对象的值是expect,则设置它的值为update。

 

参考资料:

Java多线程系列–“JUC原子类”05之 AtomicLongFieldUpdater原子类

Java中的Atomic包使用指南

    原文作者:JUC
    原文地址: http://www.cnblogs.com/2015110615L/p/6750185.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞