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

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,具有原子性和可见性。

AtomicIntegerFieldUpdater和AtomicLongFieldUpdater的独有方法与AtomicInteger和AtomicLong的独有方法类似,唯一的区别在于多了一个参数: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):增量计算,并返回新值time:3043940381384,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):自增,并返回新值time:3043940381385,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):自减,并返回新值time:3043940381384,new = 3043940381384

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

 

posted @ 2021-08-25 16:41  姚春辉  阅读(176)  评论(0编辑  收藏  举报