一.Atomic包,提供了单个变量上解除锁的线程安全编程。事实上,此包中的类可将volatile值、字段和数组元素的概念扩展到那些提供原子性操作的类上,主要方式为 compareAndSet(expectedValue,updateValue),
即CAS思想来确保内存一致性操作。expectedValue即当前值,updateValue为需要被更新的值,如果内存中的值为expectedVaue则更新,否则返回false。这些方法的实现基于处理器提供的高效机器级别原子性指令;由于平台的不同,cas的系统级别的底层实现,可能会基于锁,可能会阻塞线程。
除了包含表示单个值的类之外,此包还包含 Updater 类,该类可用于获取任意选定类的任意选定 volatile 字段上的 compareAndSet 操作。
AtomicReferenceFieldUpdater、AtomicIntegerFieldUpdater 和 AtomicLongFieldUpdater 是基于反射的实用工具,可以提供对关联字段类型的访问。它们主要用于原子数据结构中,该结构中同一节点(例如,树节点的链接)的几个 volatile 字段都独立受原子更新控制。这些类在如何以及何时使用原子更新方面具有更大的灵活性,但相应的弊端是基于映射的设置较为拙笨、使用不太方便,而且在保证方面也较差。
原子类也支持 weakCompareAndSet 方法,该方法具有受限制的适用性。在某些平台上,弱版本在正常情况下可能比 compareAndSet 更有效,但不同的是 weakCompareAndSet 方法的任何给定调用可能意外 返回 false(即没有明确的原因)。返回 false 仅意味着可以在需要时重新尝试操作,具体取决于重复执行调用的保证,当该变量保持 expectedValue 并且没有其他线程也在尝试设置该变量时,最终将获得成功。(例如,这样的虚假失败可能是由于内存争用的结果,该争用与期望值和当前值是否相等无关)。 此外,weakCompareAndSet 不提供通常需要同步控制的排序保证。但是,在这样的更新与程序的其他 happen-before 排序不相关时,该方法可用于更新计数器和统计数据。当一个线程看到对 weakCompareAndSet 导致的原子变量的更新时,它不一定能看到在 weakCompareAndSet 之前发生的对任何其他 变量的更新。例如,在更新性能统计数据时,这也许可以接受,但其他情况几乎不可以。
AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray 类进一步扩展了原子操作,对这些类型的数组提供了支持。
这些类在为其数组元素提供 volatile 访问语义方面也引人注目,这对于普通数组来说是不受支持的。
Atomic的各种类,并没有统一的接口,他们却都具有几乎相同的操作方法。
AtomicBoolean,AtomicInteger,AtomicLong内部实现基本一致。以AtomicInteger为例,其底层为一个volatile int作为数据存储,并通过unsafe API的compareAndSwap方式尝试更新数据。
- void set(newValue)/void lazySet(newValue):设置新值,采用非原子性操作,直接设置新值。lazySet主要是更新操作,并非立即执行,而是根据CPU调度(操作有序化),会在适当的时候被执行,比如在多核cpu中,此值不具有竞争性修改时,执行lazySet。。一种简单的non-blocking操作。
- void getAndSet(newValue):通过cas方式设置新值,并返回修改之前的值。///
for (;;) { int current = get(); if (compareAndSet(current, newValue)) return current; } }
- final boolean compareAndSet(int expect, int update):CAS方式设置新值,设置成功返回true。底层使用unsafe.compareAndSwapInt(..)
- final boolean weakCompareAndSet(int expect, int update):对于AtomicInteger/AtomicLong,AtomicBoolean/AtomicReference,此方法的实现和compareAndSet一模一样。所以此方法,可能再其他地方有不同的实现,再次不再赘言。
二.AtomicReference:原子性的更新对象引用。
AtomicMarkableReference:此API设计的作用非常简单,原子性的更新对象引用以及其标记位(boolean属性),将一个对象引用和一个boolean属性捆绑,内部通过AtomicReference来实现。
比如:AtomicMarkableReference(T reference,boolean initialMark),此构造函数则构建一个reference并使其具有initialMark的状态。
- public V getReference():返回绑定的reference。
- public boolean isMarked():返回标记为状态
- public boolean compareAndSet(V expectedReference,V newReference,boolean expectedMark,boolean newMark):CAS方式更新reference和mark位,只有当reference和mark为都为期望值时,才更新为新值。
- public void set(V newReference, boolean newMark) :强制设置新的reference和mark位。
同样,AtomicStampedReference类和AtomicMarkableReference功能几乎完全一样,只不过AtomicStampedReference的“标志位”是一个int型,其API方法基本一样。AtomicStampedReference(V initialRef, int initialStamp):创建对象,使其初始引用和标记位为initialStamp。
三.AtomicReferenceFieldUpdater<T,V>
此类为抽象类,其提供了内置的实现方式。此类基于反射可以对指定类的指定 volatile 字段进行原子更新。
该类用于原子数据结构,该结构中同一节点的几个引用字段都独立受原子更新控制。我们之前看到的Atomic的类型API,只能对一种类型数据进行原子性操作。此类提供了可以针对一个class中多个volatile字段,
进行原子性更行的可能。不过AtomicReferenceFieldUpdater只能适用于类的一个属性。
class Node { private volatile Node left, right; private static final AtomicReferenceFieldUpdater leftUpdater = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); private static AtomicReferenceFieldUpdater rightUpdater = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); Node getLeft() { return left; } boolean compareAndSetLeft(Node expect, Node update) { return leftUpdater.compareAndSet(this, expect, update); } // ... and so on }
- public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,Class<W> vclass,String fieldName):使用给定的字段为对象创建和返回一个更新器。需要 Class 参数检查反射类型和一般类型是否匹配。如果指定字段非volatile,将抛出异常。
- boolean compareAndSet(T obj,V expect,V update):原子性的更新对象的属性值。