同步数据结构之原子字段类

引言

接下来是原子类序章中我们提到的原子更新字段类,它们是AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater。其实就是了原子的更新一个引用类型的整形字段、long型字段、引用类型字段。

 

AtomicIntegerFieldUpdater

首先根据如下的类结构可见,它本身是一个抽象方法,提供了一个静态工厂方法newUpdater()来生成实例。

 1 public abstract class AtomicIntegerFieldUpdater<T> {  
 2   
 3 @CallerSensitive  
 4 public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {  
 5     return new AtomicIntegerFieldUpdaterImpl<U>  
 6         (tclass, fieldName, Reflection.getCallerClass());  
 7 }  
 8   
 9 /** 
10  * Protected do-nothing constructor for use by subclasses. 
11  */  
12 protected AtomicIntegerFieldUpdater() {  
13 }  
14 .....  

接着来看它的实现类,它的实现类AtomicIntegerFieldUpdaterImpl是它的一个私有静态内部类:

 1 private static class AtomicIntegerFieldUpdaterImpl<T>  
 2     extends AtomicIntegerFieldUpdater<T> {  
 3         private static final Unsafe unsafe = Unsafe.getUnsafe();  
 4         private final long offset;  
 5         private final Class<T> tclass;  
 6         private final Class<?> cclass;  
 7   
 8         AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,  
 9                                   final String fieldName,  
10                                   final Class<?> caller) {  
11         final Field field;  
12         final int modifiers;  
13         try {  
14             field = AccessController.doPrivileged(  
15                 new PrivilegedExceptionAction<Field>() {  
16                     public Field run() throws NoSuchFieldException {  
17                         return tclass.getDeclaredField(fieldName);  
18                     }  
19                 });  
20             modifiers = field.getModifiers();  
21             sun.reflect.misc.ReflectUtil.ensureMemberAccess(  
22                 caller, tclass, null, modifiers);  
23             ClassLoader cl = tclass.getClassLoader();  
24             ClassLoader ccl = caller.getClassLoader();  
25             if ((ccl != null) && (ccl != cl) &&  
26                 ((cl == null) || !isAncestor(cl, ccl))) {  
27               sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);  
28             }  
29         } catch (PrivilegedActionException pae) {  
30             throw new RuntimeException(pae.getException());  
31         } catch (Exception ex) {  
32             throw new RuntimeException(ex);  
33         }  
34   
35         Class<?> fieldt = field.getType();  
36         if (fieldt != int.class)  
37             throw new IllegalArgumentException("Must be integer type");  
38   
39         if (!Modifier.isVolatile(modifiers))  
40             throw new IllegalArgumentException("Must be volatile type");  
41   
42         this.cclass = (Modifier.isProtected(modifiers) &&  
43                        caller != tclass) ? caller : null;  
44         this.tclass = tclass;  
45         offset = unsafe.objectFieldOffset(field);  
46     }  
47 .....  

从它的实例构造方法可见,它首先会对目标class及其指定的字段进行检测,主要是访问权限、数据类型是否是int,是否 是volatile修饰,最后当然还有通过unsafe获取目标字段的偏移量,为后面的CAS原子操作作准备。

从以上方法我们可以得出,要想使用AtomicIntegerFieldUpdater原子的更新一个对象的某个字段,必须满足以下条件:

  1. 调用者必须有对目标类的访问权限;
  2. 目标字段必须是整形int或者Integer;
  3. 目标字段必须是public修饰的;
  4. 目标字段必须是volatile修饰的。

另外,实现类AtomicIntegerFieldUpdaterImpl还实现了一些AtomicIntegerFieldUpdater的基础的原子更新的抽象方法:

 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 }  
 5   
 6 public boolean weakCompareAndSet(T obj, int expect, int update) {  
 7     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
 8     return unsafe.compareAndSwapInt(obj, offset, expect, update);  
 9 }  
10   
11 public void set(T obj, int newValue) {  
12     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
13     unsafe.putIntVolatile(obj, offset, newValue);  
14 }  
15   
16 public void lazySet(T obj, int newValue) {  
17     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
18     unsafe.putOrderedInt(obj, offset, newValue);  
19 }  
20   
21 public final int get(T obj) {  
22     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
23     return unsafe.getIntVolatile(obj, offset);  
24 }  
25   
26 public int getAndSet(T obj, int newValue) {  
27     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
28     return unsafe.getAndSetInt(obj, offset, newValue);  
29 }  
30   
31 public int getAndIncrement(T obj) {  
32     return getAndAdd(obj, 1);  
33 }  
34   
35 public int getAndDecrement(T obj) {  
36     return getAndAdd(obj, -1);  
37 }  
38   
39 public int getAndAdd(T obj, int delta) {  
40     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
41     return unsafe.getAndAddInt(obj, offset, delta);  
42 }  
43   
44 public int incrementAndGet(T obj) {  
45     return getAndAdd(obj, 1) + 1;  
46 }  
47   
48 public int decrementAndGet(T obj) {  
49      return getAndAdd(obj, -1) - 1;  
50 }  
51   
52 public int addAndGet(T obj, int delta) {  
53     return getAndAdd(obj, delta) + delta;  
54 }

这些方法和AtomicInteger提供的方法一致,不再熬述。剩下的其他的一些方法和AtomicInteger提供的原子更新方法几乎一样,都分为那四大原子更新方法,也不在一一列举。

AtomicLongFieldUpdater

再看AtomicLongFieldUpdater,它和AtomicIntegerFieldUpdater的结构基本一致,也是一个抽象方法,不同的是它是对long型字段的原子更新,而不是整形。

 

另外还有一个比较重要的区别就是,它的实现类有两个,根据平台是否支持8字节的CAS操作来选择不同的实现:

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

如果平台支持8字节的CAS操作,那么实现逻辑 CASUpdater就和AtomicIntegerFieldUpdater中的实现类似,也就是直接使用CAS操作达到原子操作的目的,如果平台不支持8字节的CAS操作,那么就使用内部加锁的方式实现对8字节的原子更新操作,如下所示为当平台不支持8字节的CAS操作时的内部加锁实现方式:

 1 public boolean compareAndSet(T obj, long expect, long update) {  
 2     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
 3     synchronized (this) {  
 4         long v = unsafe.getLong(obj, offset);  
 5         if (v != expect)  
 6             return false;  
 7         unsafe.putLong(obj, offset, update);  
 8         return true;  
 9     }  
10 }  
11   
12 public boolean weakCompareAndSet(T obj, long expect, long update) {  
13     return compareAndSet(obj, expect, update);  
14 }  
15   
16 public void set(T obj, long newValue) {  
17     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
18     synchronized (this) {  
19         unsafe.putLong(obj, offset, newValue);  
20     }  
21 }  
22   
23 public void lazySet(T obj, long newValue) {  
24     set(obj, newValue);  
25 }  
26   
27 public long get(T obj) {  
28     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);  
29     synchronized (this) {  
30         return unsafe.getLong(obj, offset);  
31     }  
32 }  

可见当不支持8字节的CAS操作时,JDK8采用的是synchronized锁实现。

 

AtomicLongFieldUpdater和AtomicIntegerFieldUpdater一样,可以对所操作的字段进行加减和更复杂的函数式运算,具体方法和AtomicLong类似,不再一一列举了。

 

AtomicReferenceFieldUpdater

最后再看AtomicReferenceFieldUpdater,它同样是一个抽象类,也是通过一个工厂方法生成原子更新器实例,同样它的实现方法也是通过CAS实现,所要操作的字段也必须是特定类型的public volatile修饰的。

 

AtomicReferenceFieldUpdater比 AtomicReference的原子更新操作更细粒度和更精确,它比AtomicReference这种直接更新整个对象要高效的多。

 

测试代码:

 1 public class AtomicIntegerFieldUpdaterTest {  
 2   
 3     private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater  
 4             .newUpdater(User.class, "old");  
 5   
 6     public static void main(String[] args) {  
 7         User user = new User("conan", 10);  
 8         System.out.println(a.getAndIncrement(user)); //10  
 9         System.out.println(a.get(user)); //11  
10     }  
11   
12     public static class User {  
13         private String name;  
14         public volatile int old;  
15   
16         public User(String name, int old) {  
17             this.name = name;  
18             this.old = old;  
19         }  
20   
21         public String getName() {  
22             return name;  
23         }  
24   
25         public int getOld() {  
26             return old;  
27         }  
28     }  
29 } 

 

posted @ 2021-05-11 16:56  莫待樱开春来踏雪觅芳踪  阅读(116)  评论(0)    收藏  举报