Java并发学习(九)-AtomicIntegerFieldUpdater字段原子更新类


前面讲的两个AtomicInteger和AtomicIntegerArray,这两个都是在最初设计编码时候就已经考虑到了需要保证原子性。但是往往有很多情况就是,由于需求的更改,原子性需要在后面加入,类似于我不要求你这整个类操作具有原子性,我只要求你里面一个字段操作具有原子性。没错,concurrent.atomic包下AtomicIntegerFieldUpdater就是这个作用的。

AtomicXXXFieldUpdater主要包括以下几个:AtomicIntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater

What is AtomicIntegerFieldUpdater

相信前言部分讲的已经很清晰易懂了,AtomicIntegerFieldUpdater就是用来更新某一个实例对象里面的int属性的。
但是注意,在用法上有规则:

  • 字段必须是volatile类型的,在线程之间共享变量时保证立即可见
  • 字段的描述类型( 修饰符public/protected/default/private )是与调用者与操作对象字段的关系一致。 也就是说调用者能够直接操作对象字段 ,那么就可以反射进行原子操作。
  • 对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
  • 只能是实例变量,不能是类变量,也就是说不能加static关键字。
  • 只能是可修改变量,不能使final变量,因为final的语义就是不可修改。
  • 对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。

具体规则可以通过以下测试例子来分析:

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

    public class AtomicIntegerFieldUpdaterAnalyzeTest {

        public static void main(String[] args) {
            AtomicIntegerFieldUpdaterAnalyzeTest test = new AtomicIntegerFieldUpdaterAnalyzeTest();
            test.testValue();
        }

        public AtomicIntegerFieldUpdater<DataDemo> updater(String name) {
            return AtomicIntegerFieldUpdater.newUpdater(DataDemo.class, name);
        }

        public void testValue() {
            DataDemo data = new DataDemo();
    //      //访问父类的public 变量,报错:java.lang.NoSuchFieldException
    //      System.out.println("fatherVar = "+updater("fatherVar").getAndIncrement(data));
    //      
    //      //访问普通 变量,报错:java.lang.IllegalArgumentException: Must be volatile type
    //      System.out.println("intVar = "+updater("intVar").getAndIncrement(data));

    //      //访问public volatile int 变量,成功
    //      System.out.println("publicVar = "+updater("publicVar").getAndIncrement(data));
    //      
    //      //访问protected volatile int 变量,成功
    //      System.out.println("protectedVar = "+updater("protectedVar").getAndIncrement(data));
    //      
    //      //访问其他类private volatile int变量,失败:java.lang.IllegalAccessException
    //      System.out.println("privateVar = "+updater("privateVar").getAndIncrement(data));
    //      
    //      //访问,static volatile int,失败,只能访问实例对象:java.lang.IllegalArgumentException
    //      System.out.println("staticVar = "+updater("staticVar").getAndIncrement(data));
    //      
    //      //访问integer变量,失败, Must be integer type
    //      System.out.println("integerVar = "+updater("integerVar").getAndIncrement(data));
    //      
    //      //访问long 变量,失败, Must be integer type
    //      System.out.println("longVar = "+updater("longVar").getAndIncrement(data));

            //自己在自己函数里面可以访问自己的private变量,所以如果可见,那么可以进行原子性字段更新
            data.testPrivate();
        }
    }
    class Father{
        public volatile int fatherVar = 4;
    }
    class DataDemo extends Father {

        public int intVar = 4;

        public volatile int publicVar = 3;
        protected volatile int protectedVar = 4;
        private volatile int privateVar = 5;

        public volatile static int staticVar = 10;
        //The field finalVar can be either final or volatile, not both
        //public final volatile int finalVar = 11;

        public volatile Integer integerVar = 19;
        public volatile Long longVar = 18L;

        public void testPrivate(){
            DataDemo data = new DataDemo();
            System.out.println(AtomicIntegerFieldUpdater.newUpdater(DataDemo.class, "privateVar").getAndIncrement(data));
        }

实现

首先看定义:

/**
     * 允许一个已经定义的类里面的某一个volatile int型变量的原子更新。
     * 注意只能够原子更新里面的某一个int型的变量。
     * 思路是通过反射获取变量,为一个updater,然后进行更新。
     */
    public abstract class AtomicIntegerFieldUpdater<T>

AtomicIntegerFieldUpdater是一个抽象类,但是它内部有一个private final类型的默认子类,所以在调用newUpdater的时候,会用模式子类来实现:

/**
         * 创建一个updater,
         * tclass:包含类的名称
         * fieldName:字段名字
         */
        @CallerSensitive
        public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
                                                                  String fieldName) {
            return new AtomicIntegerFieldUpdaterImpl<U>
                (tclass, fieldName, Reflection.getCallerClass());
        }

而除了这些之外,子类中还有判断对象访问权限,以及判断是否为父类,是否同一个包等方法:

//判断second是否为first的父类
    private static boolean isAncestor(ClassLoader first, ClassLoader second) ;
    //判断class1和class2是否在同一个包下
    private static boolean isSamePackage(Class<?> class1, Class<?> class2)
    //获得包名
    private static String getPackageName(Class<?> cls)
    //判断object是否为当前class的一个子类
    private final void accessCheck(T obj)

另外就是一些CAS方法,实际上都是调用Unsafe.java中的native方法:

public final boolean compareAndSet(T obj, int expect, int update) {
                accessCheck(obj);
                return U.compareAndSwapInt(obj, offset, expect, update);
            }

            public final boolean weakCompareAndSet(T obj, int expect, int update) {
                accessCheck(obj);
                return U.compareAndSwapInt(obj, offset, expect, update);
            }

            public final void set(T obj, int newValue) {
                accessCheck(obj);
                U.putIntVolatile(obj, offset, newValue);
            }

            public final void lazySet(T obj, int newValue) {
                accessCheck(obj);
                U.putOrderedInt(obj, offset, newValue);
            }

            public final int get(T obj) {
                accessCheck(obj);
                return U.getIntVolatile(obj, offset);
            }

            public final int getAndSet(T obj, int newValue) {
                accessCheck(obj);
                return U.getAndSetInt(obj, offset, newValue);
            }

AtomicLongFieldUpdater和AtomicReferenceFieldUpdater

在AtomicLongFieldUpdater类中,由于有些32位系统一次性无法对64位的long进行原子运算,所以为了保证安全,在这些不能一次性进行原子运算的需要区分考虑,利用加synchronized锁来实现:

@CallerSensitive
        public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
                                                               String fieldName) {
            Class<?> caller = Reflection.getCallerClass();
            if (AtomicLong.VM_SUPPORTS_LONG_CAS)
            //直接cas实现
                return new CASUpdater<U>(tclass, fieldName, caller);
            else
            //带synchronized锁实现
                return new LockedUpdater<U>(tclass, fieldName, caller);
        }

什么意思呢?下面给出几个具体方法:

直接CAS实现:

//直接CAS实现
            public final boolean compareAndSet(T obj, long expect, long update) {
                accessCheck(obj);
                return U.compareAndSwapLong(obj, offset, expect, update);
            }

加锁的CAS实现:

//加锁的CAS实现
            public final boolean compareAndSet(T obj, long expect, long update) {
                accessCheck(obj);
                synchronized (this) {
                    long v = U.getLong(obj, offset);
                    if (v != expect)
                        return false;
                    U.putLong(obj, offset, update);
                    return true;
                }
            }

在其他方面, AtomicLongFieldUpdaterAtomicReferenceFieldUpdater实现思想基本一致。


原文链接:https://blog.csdn.net/anLA_/article/details/78662383?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param