JUC 原子类

标签: juc 子类 | 发表时间:2013-11-20 22:57 | 作者:
出处:http://www.iteye.com

 

原文地址: http://coderbee.net/index.php/java/20131117/581

 

volatile 变量

volatile变量具有可见性,也就是说线程能够自动发现volatile 变量的最新值;对volatile变量进行操作不会造成阻塞。

适用于:多个变量之间或者某个变量的当前值与修改后值之间没有约束。

正确使用volatile变量的条件:

  1. 对变量的写操作不依赖于当前值。
  2. 该变量没有包含在具有其他变量的不变式中。

所以,volatile变量不支持像 i++这样的原子操作,因为这条语句包含了三个步骤:读取-加1操作-写变量。

CAS操作

大多数CPU都提供了CAS操作指令,这条指令的作用是:对于一个变量var,如果它的当前值是excepted,则把它的值更新为newValue,否则就不更新。

由于JVM屏蔽了操作系统有关的细节,HotSpot虚拟机通过 sun.misc.Unsafe类提供了这样的操作指令。

原子类

原子类是对volatile变量的增强,提供了一些稍微复杂的符合操作,如上面提到的 i++操作。这里以 java.util.concurrent.atomic.AtomicInteger为例。

直接读写操作

AtomicInteger有一个 volatile int value属性表示对象的值,这样,对变量的读写操作就可以借助volatile语义直接完成。

   public final int get() {
     return value;
}

public final void set(int newValue) {
     value = newValue;
}

CAS操作

compareAndSet是通过unsafe类的本地方法来实现的,这个方法也是实现其他复合操作的方法的基础。

   public final boolean compareAndSet(int expect, int update) {
     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

对变量的加减操作

CPU虽然提供了CAS这样的操作指令,但并没有提供类似这样的操作:对变量加一个指定的值,再返回旧值。但AtomicInteger类却能够提供,下面就看看里面的魔法:

   public final int getAndAdd(int delta) {
     for (;;) {
          int current = get(); //step 1
          int next = current + delta; //step 2
          if (compareAndSet(current, next)) //step 3
               return current;
     }
}

这个方法很简洁,在一个无穷的循环里面不断尝试这样的操作序列:先取变量的当前值,进行加操作,然后用CAS操作设置新的值,如果设置成功则返回,否则继续尝试。

这里之所以要放到一个无穷循环里进行操作,是因为step 1之后,step 3成功之前,变量的值都有可能被改变,只要变量的值被其他线程修改了,就需要重试。但只要线程之间的写竞争不激烈,这个操作序列就总会成功。

总的来说,原子类的复合操作的实现思路是:CAS + 失败后不断重试。

其他的类似操作也是采用这样的思路实现的。

ABA问题

在上面的 getAndAdd方法的实现里,线程T执行step1后、执行step3之前被挂起,另一个线程T2把 value属性从A修改为B,然后又修改回A,那么T恢复执行时,它是不会发现 value曾经被修改,继续执行step 3是成功的。这个问题就是ABA问题。

ABA问题的解决思路是给变量的值关联一个戳记,每次修改变量的值时同时改变戳记,那么即使变量的值不变也可以发现它是否被修改过。

AtomicBoolean

这里要特别说下的是AtomicBoolean的实现。boolean只能表示true或false,只需要一个比特位就够了,但所有CPU都不直接读写某个比特位,最小的也是字节。

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [juc 子类] 推荐:

JUC 原子类

- - ITeye博客
volatile变量具有可见性,也就是说线程能够自动发现volatile 变量的最新值;对volatile变量进行操作不会造成阻塞. 适用于:多个变量之间或者某个变量的当前值与修改后值之间没有约束. 正确使用volatile变量的条件:. 对变量的写操作不依赖于当前值. 该变量没有包含在具有其他变量的不变式中.

JUC CyclicBarrier 可重用屏障

- - 码蜂笔记
CyclicBarrier 是一个线程同步工具,用于一组互相等待线程之间的协调,在到达某个临界点之前,这些线程必须互相等待,在通过临界点之后,这些线程是独立的;CountDownLatch 是让一个线程等待其他线程完成某些任务,其他线程之间一直是独立的. CyclicBarrier 还允许指定一个任务,在所有线程到达临界点时执行,由最后到达的线程执行此任务.