Atomic并发API简述

一.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):原子性的更新对象的属性值。

你可能感兴趣的:(atomic)