Java并发23:Atomic系列-普通原子类型AtomicXxxx学习笔记
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 - ---------------------------------------------------------