并发编程九继续探索j​.u.c​中的Atomic12个原子操作

99 阅读4分钟
原文链接: mp.weixin.qq.com

今天继续探索j.u.c中的12个原子操作Atomic,可以进行分为四组。基本类型、数组类型、引用类型、属性类型。这些类都是采用Unsafe中的方法进行实现。

基本类型


Atomic提供以下几个类

  • AtomicBoolean

  • AtomicLong

  • AtomicInteger

它们的实现方法都类似,采用Unsafe实现,如AtomicInteger为例

static {    try {        valueOffset = unsafe.objectFieldOffset            (AtomicInteger.class.getDeclaredField("value"));    } catch (Exception ex) { throw new Error(ex); }}

上面代码是根据类中‘‘value’’字段取内存地址,而value采用 volatile字段进行修饰

private volatile int value;

AtomicInteger主要方法

  • get()        //获取值

  • getAndIncrement()        //当前值加1, 并返回 旧值

  • getAndDecrement()      //当前值减1,并返回 旧值

  • incrementAndGet()      //当前值加1并返回新值

  • decrementAndGet()     //当前值减1并返回新值

  • compareAndSet(expect,update)     //当前值为预期值时, 更新新值

面试题

  1. 请回答以下代码的值分别是什么 ?

public class AtomicIntegerDemo {    public static void main(String[] args) {        AtomicInteger atomic = new AtomicInteger();        System.out.println(atomic.getAndIncrement());        System.out.println(atomic.incrementAndGet());        atomic.lazySet(4);        System.out.println(atomic.compareAndSet(2,4));        System.out.println(atomic.get());    }}

2.为什么AtomicBoolean源码中value为什么是int类型?

数据类型


Atomic提供以下几个类:

  • AtomicIntegerArray

  • AtomicLongArray

  • AtomicReferenceArray

采用原子数组方式实现

private static final int shift;private final int[] array;static {    int scale = unsafe.arrayIndexScale(int[].class);    if ((scale & (scale - 1)) != 0)        throw new Error("data type scale not a power of two");    shift = 31 - Integer.numberOfLeadingZeros(scale);}

AtomicIntegerArrary主要的方法:

  • addAndGet   //对指定下标的值进行两值相加并返回

  • compareAndSet   //对指定下标的值,若为期待值时进行赋值返回 true

  • get  //返回指定下标的值

  • getAndIncrement 

  • incrementAndGet

  • getAndDecrement

  • decrementAndGet

AtomicReferenceArray构造方法必须有参数,初始化组数长度。在每次操作时跟数组操作是一样的,每次操作都要带着下标去操作方法

AtomicReferenceArray<User> array = new AtomicReferenceArray<>(1);

面试题

1.请回答以下代码输出结果是什么?

public class AtomicIntegerArrayDemo {    public static void main(String[] args) {        int[] v =new int[]{1,2};        AtomicIntegerArray array = new AtomicIntegerArray(v);        System.out.println(array.addAndGet(0,3));        System.out.println(array.get(0));        System.out.println(array.compareAndSet(1,2,10));        System.out.println(array.get(1));    }}

引用类型


Atomic提供以下几个类

  • AtomicReference  //原子引用类型

  • AtomicMarkableReference    //带有标记位的引用类型

  • AtomicStampedReference //带有版本号的引用类型

AtomicReference的实现方式与基本类型实现相同,但不同的是V是可变对象,而不像基本类型那样是具体的基本类型。

static {    try {        valueOffset = unsafe.objectFieldOffset            (AtomicReference.class.getDeclaredField("value"));    } catch (Exception ex) { throw new Error(ex); }}private volatile V value;

AtomicMarkableReference是解决ABA的问题, 它不关心版本号,关心的是数据是否有变化

private static class Pair<T> {    final T reference;    final boolean mark;    private Pair(T reference, boolean mark) {        this.reference = reference;        this.mark = mark;    }    static <T> Pair<T> of(T reference, boolean mark) {        return new Pair<T>(reference, mark);    }}private volatile Pair<V> pair;

AtomicStampedReference的实现与AtomicMarkableReference的实现类似。也是解决ABA问题,

private static class Pair<T> {    final T reference;    final int stamp;    private Pair(T reference, int stamp) {        this.reference = reference;        this.stamp = stamp;    }    static <T> Pair<T> of(T reference, int stamp) {        return new Pair<T>(reference, stamp);    }}private volatile Pair<V> pair;

属性类型


Atomic提供以下几个类

  • AtomicIntegerFieldUpdater   //整型字段更新器

  • AtomicLongFieldUpdater     //长整型字段更新器

  • AtomicReferenceFieldUpdater   //引用字段的更新器

AtomicIntegerFieldUpdater主要方法

  • newUpdater

  • incrementAndGet

  • getAndIncrement

  • getAndDecrement

  • get

  • getAndAdd

  • getAndSet

  • decrementAndGet

  • lazySet

这些方法的原理跟上面的类都差不多,这里就不加注释了非常好理解。

AtomicIntegerFieldUpdater是个抽象类,不通过直接new对象,而需要使用静态方法创建对象, 请看源码

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

在newUpdater  方法以下几个要求

  • 第一个参数是个类类型

  • 第二个参数是 更新的字段名

  • 字段名必须是volatile int 进行修饰

示例代码,顺序请回答下结果

public class AtomicIntegerFieldUpdaterDemo {    public static void main(String[] args) {        AtomicIntegerFieldUpdater<User> updater =                AtomicIntegerFieldUpdater.newUpdater(User.class, "name");        System.out.println(updater.get(new User()));        System.out.println(updater.incrementAndGet(new User()));        System.out.println(updater.getAndIncrement(new User()));    }    static class User {        volatile int name;    }}

AtomicReferenceFieldUpdater 的常用方法

  • newUpdater   //

  • get   //获取指定对象字段的值

  • set  //设置指定对象字段的值

  • getAndAccumulate  //通过指定对象的值与当前值进行计算,返回旧值

  • getAndSet   //设置指定对象字段的值,返回旧值

  • getAndUpdate  //1.8 计算 返回 旧值

  • lazySet

示例代码,并回答下执行结果

public class AtomicReferenceFieldUpdaterDemo {    public static void main(String[] args) {        AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(User.class,String.class        ,"name");        User user = new User();        user.name = "hello";        System.out.println(updater.getAndAccumulate(user, "java",new BinaryOperator<String>() {            @Override            public String apply(String s, String s2) {                return s+" "+s2;            }        }));        System.out.println(updater.getAndUpdate(user,(x)->x+" word"));        System.out.println(user.name);    }    static class User{       volatile String name;    }}

以上是根据个人理解做了分析,如有不正确请留言讨论。

----------------------------------------------------------

再次感谢,欢迎关注微信公众号“零售云技术”,文章持续更新,或留言讨论