Java并发25:Atomic系列-原子类型字段更新器AtomicXxxxFieldUpdater学习笔记

时间:2021-02-13 14:55:28

[超级链接:Java并发学习系列-绪论]
[系列概述: Java并发22:Atomic系列-原子类型整体概述与类别划分]


本章主要对原子类型字段更新器进行学习。

1.原子类型字段更新器

java.util.concurrent.atomic中,原子类型字段更新器有以下三种:

  • AtomicIntegerFieldUpdater:基于反射的工具类,可以原子性的更新指定对象指定int类型字段
  • AtomicLongFieldUpdater:基于反射的工具类,可以原子性的更新指定对象指定long类型字段
  • AtomicReferenceFieldUpdater:基于反射的工具类,可以原子性的更新指定对象指定应用类型字段

2.使用规则浅谈

原子类型字段更新器在内部通过Unsafe类native方法保证操作的原子性

关于原子类型字段更新器的使用需要注意一下几个方面:

  • 字段必须是volatile类型的,用于保证可见性
  • 字段字段更新器的访问类型(public/protected/private)必须一致。
  • 字段只能是实例变量,不能是类变量(static)。
  • 字段不能是final的变量,这样的字段不可修改。
  • 如果要处理Integer和Long类型,则需要使用AtomicReferenceFieldUpdater

3.原子类型字段更新器的通用方法

首先学习上述三种原子类型字段更新器的通用方法,这些方法如下:

  • 构造器:只有一个无参protected的构造函数,并不可用。
  • newUpdater(fieldClass,fieldName):原子类型字段更新器提供的一个静态泛型方法,用于创建和返回指定字段和指定类型的原子类型字段更新器实例对象。
  • get(obj):赋值,具有原子性可见性
  • set(obj):取值,具有原子性可见性
  • lazySet(obj,newValue):赋值,具有原子性,不具备可见性
  • getAndSet(obj,newValue):赋值并返回旧值,具有原子性可见性
  • compareAndSet(obj,expect,update):如果当前是期望值则赋值并返回赋值成功与否,具有原子性可见性
  • weakCompareAndSet(obj,expect,update):与compareAndSet(obj,expect,update)类似。

原子类型字段更新器的通用方法与普通原子类型的通用方法类似,唯一的区别在于多了一个参数:obj(被修改的字段的所属对象)


场景说明:

  • 构建一个自定义类型,此类型有三个字段:键、值和创建时间。
  • 构建三个原子类型字段构造器,分别用于以上三种字段的更新操作。

实例代码:

自定义类型MyVolatileType:

/** * <p>自定义数组,用于字段更新器演示</p> * * @author hanchao 2018/3/20 22:35 **/
static class MyVolatileType {
    //自定义-键
    //必须是volatile;必须是long,不能是Long
    //用AtomicLongFieldUpdater处理
    //如果是Long的,则用AtomicReferenceFieldUpdater
    private volatile int index;
    //newUpdater(Class对象,字段名)
    //字段更新器需要与字段的访问类型一致
    private static final AtomicIntegerFieldUpdater integerFieldUpdater =
            AtomicIntegerFieldUpdater.newUpdater(MyVolatileType.class, "index");
    //自定义-值
    //必须是volatile
    //需用AtomicReferenceFieldUpdater处理
    private volatile String value;
    //newUpdater(Class对象,字段名)
    //字段更新器需要与字段的访问类型一致
    private static final AtomicLongFieldUpdater longFieldUpdater = AtomicLongFieldUpdater.newUpdater(MyVolatileType.class, "time");

    //自定义-创建时间
    //必须是volatile;必须是int,不能是Integer
    //用AtomicIntegerFieldUpdater处理
    //如果是Integer的,则用AtomicReferenceFieldUpdater
    private volatile long time;
    //newUpdater(Class对象,字段Class对象,字段名)
    //字段更新器需要与字段的访问类型一致
    private static final AtomicReferenceFieldUpdater referenceFieldUpdater =
            AtomicReferenceFieldUpdater.newUpdater(MyVolatileType.class, String.class, "value");

    @Override
    public String toString() {
        return "MyVolatileType{" +
                "index=" + index +
                ", value='" + value + '\'' +
                ", time=" + time +
                '}';
    }

    public MyVolatileType(int index, String value, long time) {
        this.index = index;
        this.value = value;
        this.time = time;
    }
}

字段更新器-通用方法演示:

/** * <p>字段更新器-通用方法演示-以AtomicReferenceFieldUpdater为例</p> * * @author hanchao 2018/3/20 22:50 **/
public void fieldUpdaterCommonMethodDemo() {
    LOGGER.info("=======字段更新器-通用方法演示-以AtomicReferenceFieldUpdater为例");
    //get(obj)
    LOGGER.info("get(obj):获取值----初始值:" + referenceFieldUpdater.get(this));
    //set(obj,newValue)
    referenceFieldUpdater.set(this, "New Day!");
    LOGGER.info("set(obj,newValue):设置值---" + referenceFieldUpdater.get(this));
    //lazySet(obj,newValue)
    referenceFieldUpdater.lazySet(this, "Lazy Day!");
    LOGGER.info("lazySet(obj,newValue):设置值(无可见性)---" + referenceFieldUpdater.get(this));
    //getAndSet(obj,newValue)
    LOGGER.info("getAndSet(obj,newValue):赋值,并返回旧值:" + referenceFieldUpdater.getAndSet(this, "Good Day!"));
    //compareAndSet(obj,expect,newValue)
    LOGGER.info("compareAndSet(obj,expect,newValue):如果是期望的值,则赋值,并返回赋值结果:"
            + referenceFieldUpdater.compareAndSet(this, "Good Day!", "Good good Day!")
            + ",---" + referenceFieldUpdater.get(this) + "\n");
}

测试代码:

MyVolatileType myArray = new MyVolatileType(1, "David", System.currentTimeMillis());
LOGGER.info("原始值:" + myArray.toString() + "\n");
//字段更新器的通用方法
myArray.fieldUpdaterCommonMethodDemo();
LOGGER.info("当前值:" + myArray.toString() + "\n");

运行结果:

2018-03-25 16:43:43 INFO  AtomicFieldUpdater:121 - 原始值:MyVolatileType{index=1, value='David', time=1521967423424}

2018-03-25 16:43:43 INFO  AtomicFieldUpdater:56 - =======字段更新器-通用方法演示-以AtomicReferenceFieldUpdater为例
2018-03-25 16:43:43 INFO  AtomicFieldUpdater:58 - get(obj):获取值----初始值:David
2018-03-25 16:43:43 INFO  AtomicFieldUpdater:61 - set(obj,newValue):设置值---New Day!
2018-03-25 16:43:43 INFO  AtomicFieldUpdater:64 - lazySet(obj,newValue):设置值(无可见性)---Lazy Day!
2018-03-25 16:43:43 INFO  AtomicFieldUpdater:66 - getAndSet(obj,newValue):赋值,并返回旧值:Lazy Day!
2018-03-25 16:43:43 INFO  AtomicFieldUpdater:68 - compareAndSet(obj,expect,newValue):如果是期望的值,则赋值,并返回赋值结果:true,---Good good Day!

2018-03-25 16:43:43 INFO  AtomicFieldUpdater:124 - 当前值:MyVolatileType{index=1, value='Good good Day!', time=1521967423424}

4.AtomicIntegerFieldUpdater和AtomicLongFieldUpdater的独有方法

然后学习AtomicIntegerFieldUpdater和AtomicLongFieldUpdater独有的一些方法,这些方法如下:

  • getAndAdd(obj):增量计算并返回旧值,具有原子性可见性
  • addAndGet(obj):增量计算并返回新值,具有原子性可见性
  • getAndIncrement(obj):自增并返回旧值,类似i ++,具有原子性可见性
  • incrementAndGet(obj):自增并返回新值,类似++ i,具有原子性可见性
  • getAndDecrement(obj):自减并返回旧值,类似i --,具有原子性可见性
  • decrementAndGet(obj):自减并返回新值,类似-- i,具有原子性可见性

AtomicIntegerFieldUpdaterAtomicLongFieldUpdater的独有方法与AtomicIntegerAtomicLong的独有方法类似,唯一的区别在于多了一个参数:obj(被修改的字段的所属对象)


实例代码:

字段更新器-int/long特殊方法演示:

/** * <p>字段更新器-int/long特殊方法演示</p> * * @author hanchao 2018/3/20 22:59 **/
public void fieldUpdaterSpecialMethodDemo() {
    LOGGER.info("=======字段更新器-int/long特殊方法演示");
    //getAndAdd(obj,delta)和addAndGet(obj,delta)
    LOGGER.info("index=" + integerFieldUpdater.getAndIncrement(this) + ",time=" + longFieldUpdater.get(this));
    LOGGER.info("getAndAdd(obj,delta):增量计算,并返回旧值index:" + integerFieldUpdater.getAndAdd(this, 2)
            + ",new = " + integerFieldUpdater.get(this));
    LOGGER.info("addAndGet(obj,delta):增量计算,并返回新值time:" + longFieldUpdater.addAndGet(this, System.currentTimeMillis())
            + ",new = " + longFieldUpdater.get(this));
    //getAndIncrement(obj)和incrementAndGet(obj)
    LOGGER.info("getAndIncrement(obj):自增,并返回旧值index:" + integerFieldUpdater.getAndIncrement(this)
            + ",new = " + integerFieldUpdater.get(this));
    LOGGER.info("incrementAndGet(obj):自增,并返回新值time:" + longFieldUpdater.incrementAndGet(this)
            + ",new = " + longFieldUpdater.get(this));
    //getAndDecrement(obj)和decrementAndGet(ojb)
    LOGGER.info("getAndDecrement(obj):自减,并返回旧值index:" + integerFieldUpdater.getAndDecrement(this)
            + ",new = " + integerFieldUpdater.get(this));
    LOGGER.info("decrementAndGet(obj):自减,并返回新值time:" + longFieldUpdater.decrementAndGet(this)
            + ",new = " + longFieldUpdater.get(this) + "\n");
}

测试代码:

MyVolatileType myArray = new MyVolatileType(1, "David", System.currentTimeMillis());
LOGGER.info("原始值:" + myArray.toString() + "\n");
myArray.fieldUpdaterSpecialMethodDemo();
LOGGER.info("当前值:" + myArray.toString() + "\n");

运行结果:

2018-03-25 17:29:50 INFO  AtomicFieldUpdater:121 - 原始值:MyVolatileType{index=1, value='David', time=1521970190687}

2018-03-25 17:29:50 INFO  AtomicFieldUpdater:79 - =======字段更新器-int/long特殊方法演示
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:81 - index=1,time=1521970190687
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:82 - getAndAdd(obj,delta):增量计算,并返回旧值index:2,new = 4
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:84 - addAndGet(obj,delta):增量计算,并返回新值time3043940381384,new = 3043940381384
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:87 - getAndIncrement(obj):自增,并返回旧值index:4,new = 5
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:89 - incrementAndGet(obj):自增,并返回新值time3043940381385,new = 3043940381385
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:92 - getAndDecrement(obj):自减,并返回旧值index:5,new = 4
2018-03-25 17:29:50 INFO  AtomicFieldUpdater:94 - decrementAndGet(obj):自减,并返回新值time3043940381384,new = 3043940381384

2018-03-25 17:29:50 INFO  AtomicFieldUpdater:127 - 当前值:MyVolatileType{index=4, value='David', time=3043940381384}