源码分析:Java原子类的实现原理、使用方法

    科技2022-09-08  113

    Java原子类

    作用原子类有哪些基本类型的原子类源码分析(实现原理)Usage 引用类型的原子类源码分析(实现原理) 原子的updater源码分析(实现原理)其他

    作用

    原子类的目的就是在并发环境下保证线程安全,并且保证效率。

    原子类有哪些

    Java的原子类在java.util.concurrent.atomic包下,包内有16个类(jdk8)

    基本类型的原子类

    AtomicBooleanAtomicIntegerAtomicLong

    源码分析(实现原理)

    以AutomicInteger为例,分析源码

    public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; //offset,value的偏移量,用来计算CAS中的V static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } //成员变量value声明为volatile类型,说明了多线程下的可见性,即任何一个线程的修改,在其它线程中都会被立刻看到 private volatile int value; public AtomicInteger(int initialValue) { value = initialValue; } public AtomicInteger() { } public final int get() { return value; } public final void set(int newValue) { value = newValue; } public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } //获取当前值,set新值,通过调用unsafe的getAndSetInt方法 public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } //没看出来和下一个方法有什么区别,成功后返回期望值 public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } public final boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } //先get,然后自增 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } //先get,然后自减 public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1); } //先get,然后add,与上几个方法类似,调用unsafe.getAndInt public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta); } //与之前方法相反,注意返回值,实现的很巧妙 public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; } //顾名思义,先获取值再更新。直到CAS成功,返回prev public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; } //与上面方法类似,返回值不同 public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; } public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev; } public final int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return next; } public String toString() { return Integer.toString(get()); } }

    Usage

    试用一下,下面的代码可以看出,经过多次运行,Demo的值都是100,可以比较充分地证明AtomicInteger是线程安全的。

    package atomicClassUsage; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class Demo extends AtomicInteger implements Runnable{ public Demo(int i){ super(i); } @Override public void run() { this.addAndGet(1); } public static void main(String[] args) throws Exception { ThreadPoolExecutor pool = new ThreadPoolExecutor(10,100,0, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); Demo demo = new Demo(0); for (int i = 0; i < 100; i++) { pool.execute(demo); } TimeUnit.SECONDS.sleep(1); System.out.println(demo.get()); } }

    引用类型的原子类

    源码分析(实现原理)

    与基本类型类似,引用类型的原子类也是基于Unsafe类实现的。这里不做赘述

    原子的updater

    对字段更新的有AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

    源码分析(实现原理)

    下面以AtomicIntegerFieldUpdater为例介绍

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

    以这两个方法为例,都是调用native方法实现,通过传入偏移量参数和新值进行CAS操作。

    public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { return new AtomicIntegerFieldUpdaterImpl<U> (tclass, fieldName, Reflection.getCallerClass()); }

    上面代码是构造方法,传入String类型的field是要进行反射吗?

    AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName, final Class<?> caller) { final Field field; final int modifiers; try { 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 ((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); }

    可以看到,调用doPrivileged方法来拿到field;

    public static native <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws PrivilegedActionException;

    这个方法是native的,与系统权限有关。上一段代码可以看出,field确实是通过反射得到的。对于更新的方法与前面类似,Unsafe实现,也不赘述了。

    其他

    没有说到的原子类有用于更新数组的,Double类型的,个人猜测用法和实现原理与前面提到的基本类似,原子类先了解到这吧,以后学到新的知识再来补充。

    Processed: 0.009, SQL: 10