AtomicIntegerFieldUpdater 源码解析(基于 JDK 1.8)

23 篇文章 1 订阅

1 介绍

AtomicIntegerFieldUpdater 是将某个类 T 的某个 int 属性包装一下,使得该属性能够在多线程中保持原子性。具体使用可见第三节。

有如下的要求:

  • 只能修改对于其可见的字段;

  • 目标类的操作字段必须被volatile关键字修饰;

  • 目标类的操作字段不能被static关键字修饰;

  • 只能修改整型int的字段。

AtomicIntegerFieldUpdater 是一个抽象类,具体是由子类 AtomicIntegerFieldUpdaterImpl 实现的。默认构造器为空,一般可使用 newUpdater 来获取一个该类对象。

public abstract class AtomicIntegerFieldUpdater<T> {
     @CallerSensitive
    public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
                                                              String fieldName) {
        //Reflection.getCallerClass 在2.1节讲解
        return new AtomicIntegerFieldUpdaterImpl<U>
            (tclass, fieldName, Reflection.getCallerClass());
    }
    protected AtomicIntegerFieldUpdater() {
    }
}

大部分方法都是抽象的,一些方法如 getAndIncrement 和 incrementAndGet 实现了方法,这里仍然是 do while 自旋。但是要注意,这些方法在子类都被重写了,换句话说这些方法没有被用上。

public int getAndIncrement(T obj) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev + 1;
        } while (!compareAndSet(obj, prev, next));
        return prev;
   }

public int incrementAndGet(T obj) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev + 1;
        } while (!compareAndSet(obj, prev, next));
        return next;
    }
//其他类似的省略

2 具体实现类

AtomicIntegerFieldUpdaterImpl 是该类的子类,真正实现了该有的功能。内部有一个 Unsafe 对象以及 int 属性在类 T 的偏移量 offset,还有两个类 cclass 和 tclass。

private static final class AtomicIntegerFieldUpdaterImpl<T>
        extends AtomicIntegerFieldUpdater<T> {
        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
        private final long offset;
        /**
         * if field is protected, the subclass constructing updater, else
         * the same as tclass
         */
    	//cclass 不容易说清,具体可见 2.2 的初始化
        private final Class<?> cclass;
        /** class holding the field */
    	//tclass 就是类型 T 的类
        private final Class<T> tclass;
    	...
}

2.1 部分预备知识

首先介绍 Reflection.getCallerClass(),这里的 Reflection 指的是 sun.reflect.Reflection。这个方法的返回值在这个实现类的初始化中作为 caller 传入。

在 JDK 8 中,有两个 getCallerClass,其中一个不带参数,一个带参数。

1. 带参数的方法在 JDK 9被删除,其参数含义是

  • 0 和小于0 - 返回 Reflection类

  • 1 - 返回自己的类

  • 2 - 返回调用者的类

  • 3 4…层层上传(找不到返回null)

2. 不带参数的方法要求在使用的时候必须加上注解 @CallerSensitive,可以看在第一节调用的方法中也有该注解。

当调用该方法时返回第一个没有加 @CallerSensitive 注解的方法所在类,注意 @CallerSensitive 只在启动类加载器 bootstrap class loader 和扩展类加载器 extension class loader 加载的类中才有效。

这个方法避免了前面按照层数来获取对应类的缺陷。

另外能堵住漏洞,可以看 https://blog.csdn.net/HEL_WOR/article/details/50199797

在第三节有例子来说明这一点。

/** Returns the class of the caller of the method calling this method,
        ignoring frames associated with java.lang.reflect.Method.invoke()
        and its implementation. */
    @CallerSensitive
    public static native Class<?> getCallerClass();

    /**
     * @deprecated This method will be removed in JDK 9.
     * This method is a private JDK API and retained temporarily for
     * existing code to run until a replacement API is defined.
     */
	
    @Deprecated
    public static native Class<?> getCallerClass(int depth);

下面的方法是 java.lang.class 的方法,isAssignableFrom。

class1.isAssignableFrom(class2) 判断 class2 是不是 class1的子类或者子接口 ,是返回 true。

public native boolean isAssignableFrom(Class<?> cls);

在 AtomicIntegerFieldUpdaterImpl 中,还有几个方法要注意。

//判断 second 是不是 first 的祖先
private static boolean isAncestor(ClassLoader first, ClassLoader second) {
            ClassLoader acl = first;
            do {
                acl = acl.getParent();
                if (second == acl) {
                    return true;
                }
            } while (acl != null);
            return false;
        }
//判断 class1 和 class2 是不是在同一个包内
private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
    		// 要求两个类的类加载器一样,以及两个的包名一样
            return class1.getClassLoader() == class2.getClassLoader()
                   && Objects.equals(getPackageName(class1), getPackageName(class2));
        }
//获取包名
private static String getPackageName(Class<?> cls) {
    String cn = cls.getName();
    int dot = cn.lastIndexOf('.');
    return (dot != -1) ? cn.substring(0, dot) : "";
	}

//检查 T 类型的 obj 是不是 cclass 的实例
//也就是 T 类型是不是 cclass 的子类
private final void accessCheck(T obj) {
            if (!cclass.isInstance(obj))
                throwAccessCheckException(obj);
        }

/**
* Throws access exception if accessCheck failed due to
* protected access, else ClassCastException.
*/
//根据 cclass 和 tclass 是否相等抛出不同的异常
private final void throwAccessCheckException(T obj) {
    if (cclass == tclass)
        throw new ClassCastException();
    else
        throw new RuntimeException(
        new IllegalAccessException(
            "Class " +
            cclass.getName() +
            " can not access a protected member of class " +
            tclass.getName() +
            " using an instance of " +
            obj.getClass().getName()));
	}

2.2 初始化

AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
                                      final String fieldName,
                                      final Class<?> caller) {
            final Field field;
            final int modifiers;
            try {
                //获取名称为fieldName的Field
                field = AccessController.doPrivileged(
                    new PrivilegedExceptionAction<Field>() {
                        public Field run() throws NoSuchFieldException {
                            return tclass.getDeclaredField(fieldName);
                        }
                    });
                //获取修饰符
                modifiers = field.getModifiers();
                //判断是否能访问
                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                    caller, tclass, null, modifiers);
                //获取两个类的加载器
                ClassLoader cl = tclass.getClassLoader();
                ClassLoader ccl = caller.getClassLoader();
                //检查包访问权限
                //下面的if 我理解为 cl 是 cll 的祖先,不知道是否正确。
                if ((ccl != null) && (ccl != cl) &&
                    ((cl == null) || !isAncestor(cl, ccl))) {
                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
                }
            } catch (PrivilegedActionException pae) {
                throw new RuntimeException(pae.getException());
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
			//要求 field 是 int,而不能是 Integer
            if (field.getType() != int.class)
                throw new IllegalArgumentException("Must be integer type");
			//要求 field 必须是 volatile 的
            if (!Modifier.isVolatile(modifiers))
                throw new IllegalArgumentException("Must be volatile type");

            // Access to protected field members is restricted to receivers only
            // of the accessing class, or one of its subclasses, and the
            // accessing class must in turn be a subclass (or package sibling)
            // of the protected member's defining class.
            // If the updater refers to a protected field of a declaring class
            // outside the current package, the receiver argument will be
            // narrowed to the type of the accessing class.
    		//如果这个field是protected,且caller是tclass的子类,两个类是在同一个包
    		//则cclass 是 caller,否则是 tclass
            this.cclass = (Modifier.isProtected(modifiers) &&
                           tclass.isAssignableFrom(caller) &&
                           !isSamePackage(tclass, caller))
                          ? caller : tclass;
            this.tclass = tclass;
            this.offset = U.objectFieldOffset(field);
        }

2.3 Unsafe 相关

接下来的方法先检查accessCheck,然后调用 Unsafe 相关方法实现,不再描述。

Unsafe 可见这两篇
Unsafe 介绍(一)
unsafe 介绍(二)与CAS

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);
        }

        public final int getAndAdd(T obj, int delta) {
            accessCheck(obj);
            return U.getAndAddInt(obj, offset, delta);
        }

        public final int getAndIncrement(T obj) {
            return getAndAdd(obj, 1);
        }

        public final int getAndDecrement(T obj) {
            return getAndAdd(obj, -1);
        }

        public final int incrementAndGet(T obj) {
            return getAndAdd(obj, 1) + 1;
        }

        public final int decrementAndGet(T obj) {
            return getAndAdd(obj, -1) - 1;
        }

        public final int addAndGet(T obj, int delta) {
            return getAndAdd(obj, delta) + delta;
        }

3 实际使用

3.1 AtomicIntegerFieldUpdater 的使用

这个类名字叫做 CountTest,其中包含一个 int 型的变量 count,也有其他类型的变量。接下来要做的事是保证 CountTest 的 count 属性能够实现原子性,这里没有使用多线程,仅仅是简单的试验一下。

首先定义一个 static 的 AtomicIntegerFieldUpdater 变量 updater 包装 CountTest 的 count 属性;在修改的时候,不是直接修改 count,而是用AtomicIntegerFieldUpdater 的相关方法来修改 count,保证原子性。

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

public class CountTest {

    public static AtomicIntegerFieldUpdater<CountTest> updater = AtomicIntegerFieldUpdater.newUpdater(CountTest.class,"count");

    //这个在3.2变成 public 修饰
    private volatile int count = 0;

    private String others;
    
    public int getCount(){
        return count;
    }

    private static CountTest countTest = new CountTest();

    public static void main(String[] args) throws InterruptedException {

        if(updater.compareAndSet(countTest,0,10)){
            System.out.println("update success "+countTest.getCount());
        } else {
            System.out.println("update fail "+countTest.getCount());
        }

        if(updater.compareAndSet(countTest,0,20)){
            System.out.println("update success "+countTest.getCount());
        } else {
            System.out.println("update fail "+countTest.getCount());
        }

    }
}

3.2 Reflection.getCallerClass()

假设有这样一个类 B,在相应的方法中调用了 newUpdater 方法,由 main 启动程序,经 debug 查看初始化的过程

则 tclass 还是 Class<CountTest>,而 caller 则是 Class<B>,而后面的 cclass 是 Class<CountTest>。

import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;


public class B {
    public static AtomicIntegerFieldUpdater<CountTest> updater = null;

    private volatile int count = 100;


    @CallerSensitive
    public void  bAction() {

        //调用 newUpdater 方法
        updater = AtomicIntegerFieldUpdater.newUpdater(CountTest.class, "count");

    }
    public static void main(String[] args) throws InterruptedException {
        new B().bAction();
    }
}

如果有一个类 C,调用 B 的 bAction,注意 bAction 有一个注解 @CallerSensitive,同样 debug 查看初始化,和前面的结果一样,而不是 caller 为 Class<C>。这是因为这个注解要求启动类加载器或者是扩展类加载器加载的类才有效。

public class C {
    public static void main(String[] args) {
        new B().bAction();
    }
}

下面是我的公众号,Java与大数据进阶,分享 Java 与大数据笔面试干货,欢迎关注
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值