Java并发23:Atomic系列-普通原子类型AtomicXxxx学习笔记

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


本章主要对普通原子类型进行学习。

1.普通原子类型

java.util.concurrent.atomic中,普通的原子类型有以下四种:

  • AtomicBoolean:提供对基本数据类型boolean原子性更新操作。
  • AtomicInteger:提供对基本数据类型int原子性更新操作。
  • AtomicLong:提供对基本数据类型long原子性更新操作。
  • AtomicReference<T>:这是一个泛型类,提供对引用类型原子性更新操作。

2.内部实现浅谈

下面对原子类型的实现原理进行浅谈。

首先看一段源码:

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;

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

    private volatile int value;

    //...

    /**
     * Sets to the given value.
     *
     * @param newValue the new value
     */
    public final void set(int newValue) {
        value = newValue;
    }

    //...
        /**
     * Eventually sets to the given value.
     *
     * @param newValue the new value
     * @since 1.6
     */
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

    //...

    /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
}

从上面的源码可知,原子类型在内部使用了两种方式实现原子性可见性

  • 通过Unsafe类的本地CAS方法保证操作的原子性
  • 通过volatile关键字保证类的可见性

关于Unsafe类可自行了解。

3.原子类型的通用方法

首先学习上述四种普通原子类型的通用方法,这些方法如下:

  • 构造器:分为默认无参构造器和初值构造器。其中,无参构造器的初始默认值分别为:
    • AtomicBoolean:false
    • AtomicInteger:0
    • AtomicLong:0
    • AtomicReference<T>null
  • get():取值,具有原子性可见性
  • set():赋值,具有原子性可见性
  • lazySet(newValue):赋值,具有原子性,不具备可见性
  • getAndSet(newValue):赋值并返回旧值,具有原子性可见性
  • compareAndSet(expect,update):如果当前是期望值则赋值并返回赋值成功与否,具有原子性可见性
  • weakCompareAndSet(expect,update):与compareAndSet(expect,update)类似。

实例代码:

//构造器
LOGGER.info("===========原子类型的默认构造器:");
//默认构造器
LOGGER.info("AtomicBoolean():声明一个原子boolean类型,初始值设置为----" + new AtomicBoolean().toString());
LOGGER.info("AtomicInteger():声明一个原子int类型,初始值设置为----" + new AtomicInteger());
LOGGER.info("AtomicLong():声明一个原子long类型,初始值设置为----" + new AtomicLong().toString());
LOGGER.info("AtomicReference():声明一个原子引用类型,初始值使用默认值----" + new AtomicReference<>().toString() + "\n");
//赋值构造器
AtomicBoolean aBoolean = new AtomicBoolean(true);
AtomicInteger aInt = new AtomicInteger(1);
AtomicLong aLong = new AtomicLong(1000L);
AtomicReference<String> aStr = new AtomicReference<>("Hello World!");

//通用操作
LOGGER.info("===========原子类型的通用操作:get()/set()/getAndSet()/compareAndSet()/weakCompareAndSet()");
//获取当前的值:volatile保证可见性-基本类型取值本身是原子性的
LOGGER.info("get():设置当前的值(可见性)----now = " + aBoolean.get());
LOGGER.info("get():设置当前的值(可见性)----now = " + aInt.get());
LOGGER.info("get():设置当前的值(可见性)----now = " + aLong.get());
LOGGER.info("get():设置当前的值(可见性)----now = " + aStr.get());
LOGGER.info("---------------------------------------------------------");
//普通赋值:volatile保证可见性-基本类型赋值本身是原子性的
aBoolean.set(false);
aInt.set(10);
aLong.set(1314);
aStr.set("Good Day!");
LOGGER.info("set():获取当前的值(可见性)----now = " + aBoolean.toString());
LOGGER.info("set():获取当前的值(可见性)----now = " + aInt.toString());
LOGGER.info("set():获取当前的值(可见性)----now = " + aLong.toString());
LOGGER.info("set():获取当前的值(可见性)----now = " + aStr.toString());
LOGGER.info("---------------------------------------------------------");
//延迟赋值:通过Unsafe保证原子性,并不保证可见性,效率要高于set()
aBoolean.set(true);
aInt.set(21);
aLong.set(521);
aStr.set("Bad Day!");
LOGGER.info("lazySet(newValue):赋值(无可见性)----now = " + aBoolean.toString());
LOGGER.info("lazySet(newValue):赋值(无可见性)----now = " + aInt.toString());
LOGGER.info("lazySet(newValue):赋值(无可见性)----now = " + aLong.toString());
LOGGER.info("lazySet(newValue):赋值(无可见性)----now = " + aStr.toString());
LOGGER.info("---------------------------------------------------------");
//赋新值,并返回旧值:通过Unsafe的native方法保证[get()+set ()]操作的原子性
LOGGER.info("getAndSet(newValue):赋新值,并返回旧值----old = " + aBoolean.getAndSet(false) + " ,newValue = false ,now = " + aBoolean.toString());
LOGGER.info("getAndSet(newValue):赋新值,并返回旧值----old = " + aInt.getAndSet(5) + " ,newValue = 5 ,now = " + aInt.toString());
LOGGER.info("getAndSet(newValue):赋新值,并返回旧值----old = " + aLong.getAndSet(200L) + " ,newValue = 200L ,now = " + aLong.toString());
LOGGER.info("getAndSet(newValue):赋新值,并返回旧值----old = " + aStr.getAndSet("Ni Hao") + " ,newValue = Ni Hao! ,now = " + aStr.toString());
LOGGER.info("---------------------------------------------------------");
//比较并赋值,返回是否成功:通过Unsafe保证原子性
LOGGER.info("compareAndSet(expect,update):如果当前是期望的值则赋值----result = " + aBoolean.compareAndSet(false,true));
LOGGER.info("compareAndSet(expect,update):如果当前是期望的值则赋值----result = " + aInt.compareAndSet(6,7));
LOGGER.info("compareAndSet(expect,update):如果当前是期望的值则赋值----result = " + aLong.compareAndSet(200L,300L));
LOGGER.info("compareAndSet(expect,update):如果当前是期望的值则赋值----result = " + aStr.compareAndSet("Ni Hao!","Good Luck!"));
LOGGER.info("---------------------------------------------------------");
LOGGER.info("weakCompareAndSet(expect,update)的实现的效果与compareAndSet(expect,update)一致,但可能失败[其实不会失败,因为其源代码与后者一致。]");
LOGGER.info("---------------------------------------------------------\n");

运行结果:

2018-03-25 15:11:47 INFO  AtomicBasicDemo:23 - ===========原子类型的默认构造器:
2018-03-25 15:11:47 INFO  AtomicBasicDemo:25 - AtomicBoolean():声明一个原子boolean类型,初始值设置为----false
2018-03-25 15:11:47 INFO  AtomicBasicDemo:26 - AtomicInteger():声明一个原子int类型,初始值设置为----0
2018-03-25 15:11:47 INFO  AtomicBasicDemo:27 - AtomicLong():声明一个原子long类型,初始值设置为----0
2018-03-25 15:11:47 INFO  AtomicBasicDemo:28 - AtomicReference():声明一个原子引用类型,初始值使用默认值----null

2018-03-25 15:11:47 INFO  AtomicBasicDemo:36 - ===========原子类型的通用操作:get()/set()/getAndSet()/compareAndSet()/weakCompareAndSet()
2018-03-25 15:11:47 INFO  AtomicBasicDemo:38 - get():设置当前的值(可见性)----now = true
2018-03-25 15:11:47 INFO  AtomicBasicDemo:39 - get():设置当前的值(可见性)----now = 1
2018-03-25 15:11:47 INFO  AtomicBasicDemo:40 - get():设置当前的值(可见性)----now = 1000
2018-03-25 15:11:47 INFO  AtomicBasicDemo:41 - get():设置当前的值(可见性)----now = Hello World!
2018-03-25 15:11:47 INFO  AtomicBasicDemo:42 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:48 - set():获取当前的值(可见性)----now = false
2018-03-25 15:11:47 INFO  AtomicBasicDemo:49 - set():获取当前的值(可见性)----now = 10
2018-03-25 15:11:47 INFO  AtomicBasicDemo:50 - set():获取当前的值(可见性)----now = 1314
2018-03-25 15:11:47 INFO  AtomicBasicDemo:51 - set():获取当前的值(可见性)----now = Good Day!
2018-03-25 15:11:47 INFO  AtomicBasicDemo:52 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:58 - lazySet(newValue):赋值(无可见性)----now = true
2018-03-25 15:11:47 INFO  AtomicBasicDemo:59 - lazySet(newValue):赋值(无可见性)----now = 21
2018-03-25 15:11:47 INFO  AtomicBasicDemo:60 - lazySet(newValue):赋值(无可见性)----now = 521
2018-03-25 15:11:47 INFO  AtomicBasicDemo:61 - lazySet(newValue):赋值(无可见性)----now = Bad Day!
2018-03-25 15:11:47 INFO  AtomicBasicDemo:62 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:64 - getAndSet(newValue):赋新值,并返回旧值----old = true ,newValue = false ,now = false
2018-03-25 15:11:47 INFO  AtomicBasicDemo:65 - getAndSet(newValue):赋新值,并返回旧值----old = 21 ,newValue = 5 ,now = 5
2018-03-25 15:11:47 INFO  AtomicBasicDemo:66 - getAndSet(newValue):赋新值,并返回旧值----old = 521 ,newValue = 200L ,now = 200
2018-03-25 15:11:47 INFO  AtomicBasicDemo:67 - getAndSet(newValue):赋新值,并返回旧值----old = Bad Day! ,newValue = Ni Hao! ,now = Ni Hao
2018-03-25 15:11:47 INFO  AtomicBasicDemo:68 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:70 - compareAndSet(expect,update):如果当前是期望的值则赋值----result = true
2018-03-25 15:11:47 INFO  AtomicBasicDemo:71 - compareAndSet(expect,update):如果当前是期望的值则赋值----result = false
2018-03-25 15:11:47 INFO  AtomicBasicDemo:72 - compareAndSet(expect,update):如果当前是期望的值则赋值----result = true
2018-03-25 15:11:47 INFO  AtomicBasicDemo:73 - compareAndSet(expect,update):如果当前是期望的值则赋值----result = false
2018-03-25 15:11:47 INFO  AtomicBasicDemo:74 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:75 - weakCompareAndSet(expect,update)的实现的效果与compareAndSet(expect,update)一致,但可能失败[其实不会失败,因为其源代码与后者一致。]
2018-03-25 15:11:47 INFO  AtomicBasicDemo:76 - ---------------------------------------------------------

4.AtomicInteger和AtomicLong的独有方法

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

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

实例代码:

//AtomicInteger和AtomicLong的独有操作
LOGGER.info("===========AtomicInteger和AtomicLong的独有操作:getAndAdd()/addAndGet()/i++/++i/i--/--i");

//增量计算,并返回旧值:通过Unsafe的native方法保证[get()+add()]操作的原子性
LOGGER.info("getAndAdd(delta):增量计算,并返回旧----old = " + aInt.getAndAdd(5) + " ,delta = 5 ,now = " + aInt.toString());
LOGGER.info("getAndAdd(delta):增量计算,并返回旧----old = " + aLong.getAndAdd(5) + " ,delta = 5 ,now = " + aLong.toString());
LOGGER.info("---------------------------------------------------------");
//增量计算,并返回新值:通过Unsafe的native方法保证[add()+get()]操作的原子性
LOGGER.info("addAndGet(delta):增量计算,并返回新值----new = " + aInt.addAndGet(5) + " ,delta = 5 ,now = " + aInt.toString());
LOGGER.info("addAndGet(delta):增量计算,并返回新值----new = " + aLong.addAndGet(5) + " ,delta = 5 ,now = " + aLong.toString());
LOGGER.info("---------------------------------------------------------");
//自增,并返回旧值:通过Unsafe的native方法保证[i++]操作的原子性
LOGGER.info("getAndIncrement():自增,并返回旧值[i++]----old = " + aInt.getAndIncrement() + ",now = " + aInt.toString());
LOGGER.info("getAndIncrement():自增,并返回旧值[i++]----old = " + aLong.getAndIncrement() + ",now = " + aLong.toString());
LOGGER.info("---------------------------------------------------------");
//自增,并返回新值:通过Unsafe的native方法保证[++i]操作的原子性
LOGGER.info("incrementAndGet():自增,并返回旧值[++i]----now = " + aInt.incrementAndGet() + ",now = " + aInt.toString());
LOGGER.info("incrementAndGet():自增,并返回旧值[++i]----now = " + aLong.incrementAndGet() + ",now = " + aLong.toString());
LOGGER.info("---------------------------------------------------------");
//自减,并返回旧值:通过Unsafe的native方法保证[i--]操作的原子性
LOGGER.info("getAndDecrement():自增,并返回旧值[i--]----old = " + aInt.getAndDecrement() + ",now = " + aInt.toString());
LOGGER.info("getAndDecrement():自增,并返回旧值[i--]----old = " + aLong.getAndDecrement() + ",now = " + aLong.toString());
LOGGER.info("---------------------------------------------------------");
//自减,并返回新值:通过Unsafe的native方法保证[--i]操作的原子性
LOGGER.info("decrementAndGet():自增,并返回旧值[--i]----now = " + aInt.decrementAndGet() + ",now = " + aInt.toString());
LOGGER.info("decrementAndGet():自增,并返回旧值[--i]----now = " + aLong.decrementAndGet() + ",now = " + aLong.toString());
LOGGER.info("---------------------------------------------------------");

运行结果:

2018-03-25 15:11:47 INFO  AtomicBasicDemo:79 - ===========AtomicInteger和AtomicLong的独有操作:getAndAdd()/addAndGet()/i++/++i/i--/--i
2018-03-25 15:11:47 INFO  AtomicBasicDemo:82 - getAndAdd(delta):增量计算,并返回旧----old = 5 ,delta = 5 ,now = 10
2018-03-25 15:11:47 INFO  AtomicBasicDemo:83 - getAndAdd(delta):增量计算,并返回旧----old = 300 ,delta = 5 ,now = 305
2018-03-25 15:11:47 INFO  AtomicBasicDemo:84 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:86 - addAndGet(delta):增量计算,并返回新值----new = 15 ,delta = 5 ,now = 15
2018-03-25 15:11:47 INFO  AtomicBasicDemo:87 - addAndGet(delta):增量计算,并返回新值----new = 310 ,delta = 5 ,now = 310
2018-03-25 15:11:47 INFO  AtomicBasicDemo:88 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:90 - getAndIncrement():自增,并返回旧值[i++]----old = 15,now = 16
2018-03-25 15:11:47 INFO  AtomicBasicDemo:91 - getAndIncrement():自增,并返回旧值[i++]----old = 310,now = 311
2018-03-25 15:11:47 INFO  AtomicBasicDemo:92 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:94 - incrementAndGet():自增,并返回旧值[++i]----now = 17,now = 17
2018-03-25 15:11:47 INFO  AtomicBasicDemo:95 - incrementAndGet():自增,并返回旧值[++i]----now = 312,now = 312
2018-03-25 15:11:47 INFO  AtomicBasicDemo:96 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:98 - getAndDecrement():自增,并返回旧值[i--]----old = 17,now = 16
2018-03-25 15:11:47 INFO  AtomicBasicDemo:99 - getAndDecrement():自增,并返回旧值[i--]----old = 312,now = 311
2018-03-25 15:11:47 INFO  AtomicBasicDemo:100 - ---------------------------------------------------------
2018-03-25 15:11:47 INFO  AtomicBasicDemo:102 - decrementAndGet():自增,并返回旧值[--i]----now = 15,now = 15
2018-03-25 15:11:47 INFO  AtomicBasicDemo:103 - decrementAndGet():自增,并返回旧值[--i]----now = 310,now = 310
2018-03-25 15:11:47 INFO  AtomicBasicDemo:104 - ---------------------------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值