JDK7中AtomicInteger源码解析

来源:互联网 发布:linux语言包大全 编辑:程序博客网 时间:2024/06/07 14:58

虽然Atomic*原子类在JDK7和JDK8中很多方法的实现是存在差异的,但是都是采用无锁编程CAS实现,其底层实现由Unsafe类提供更新与实现。

1.Unsafe类概述

Java不能直接访问操作系统底层,而是通过Native本地方法来访问。Unsafe类提供了硬件级别的原子操作,主要提供了以下功能:

(a)通过Unsafe类可以分配内存,可以释放内存;

类中提供的3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存。

(b)可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的

JAVA中对象的字段的定位可能通过staticFieldOffset方法实现,该方法返回给定field的内存地址偏移量,这个值对于给定的filed是唯一的且是固定不变的。

(c)挂起与恢复

将一个线程进行挂起是通过park方法实现的,调用park后线程将一直阻塞直到超时或者中断等条件出现,unpark可以终止一个挂起的线程使其恢复正常。

(d)CAS操作

通过compareAndSwapXXX方法实现的。

Note:CAS会存在“ABA”问题,AtomicStampedReference/AtomicMarkableReference提供的版本控制机制可以有效的解决这个“ABA”问题但是效率不高(未测试是否准确?)。

 

2.AtomicInteger类概述

public class AtomicInteger extends Number implements java.io.Serializable;

// AtomicInteger只有3个成员变量

private static final Unsafe unsafe = Unsafe.getUnsafe(); // 用来实现CAS

private static final long valueOffset; // value值在内存地址中的偏移量

static { // 获取value值偏移量地址

 try {

   valueOffset = unsafe.objectFieldOffset

            (AtomicInteger.class.getDeclaredField("value"));

 } catch (Exception ex) { throw new Error(ex); }

}

private volatile int value; // AtomicInteger对应的值

 

AtomicInteger提供了两个构造函数,如下所示:

(a)AtomicInteger() // 创建具有初始值0的新AtomicInteger

(b)AtomicInteger(int initialValue){

value = initialValue; // 创建具有给定初始值的新AtomicInteger

}


3. AtomicInteger重要方法分析

AtomicInteger虽然提供了不少实现方法,但其中最重要的方法是:自增(减),两数相加,以及initValue();像其它的获取值,设置值和以某种形式返回值(继承Number类的实现方法)等方法都是辅助手段(个人理解)。由于此处实现方法类似,故只用自增和两数相加进行源码解析:

public final int getAndIncrement() {

  for (;;) { // 此处自旋,由JVM处理自旋多久

   int current = get(); // 获取当前value值

   int next = current + 1; // 设置新值

   if (compareAndSet(current, next))

     return current; // CAS实现值的更新,当前值==期望值就更新为新值

  }

}

public final int incrementAndGet() {

  for (;;) {

   int current = get();

   int next = current + 1;

   if (compareAndSet(current, next))

     return next;

  }

}

由源码可以看出getAndIncrement和incrementAndGet两者的实现差异只是返回值不同,此处的实现差异类似i++和++i。此处decrementAndGet和getAndDecrement实现方法类似自增,只是next的取值是:current-1。

 

public final int getAndAdd(int delta) {

  for (;;) {

    int current = get();

    int next = current + delta;

    if (compareAndSet(current, next))

      return current;

  }

}

public final int addAndGet(int delta) {

  for (;;) {

    int current = get();

    int next = current + delta;

    if (compareAndSet(current, next))

      return next;

  }

}

由源码可以看出此处的实现类似getAndIncrement和incrementAndGet,只是这里把自增的值替换为传入的delta值。

 

public int intValue() {

  return get();  // 返回value值

}

 

Note:继承Number类,实现以什么形式返回值,只需要将返回值进行强行转换即可,例如以long形式的返回:(long)get()。

public final int get() {

  return value;

}

 

// CAS更新值,当前值==期望值则返回更新的值

public final boolean compareAndSet(int expect, int update) {

    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

}

public final boolean weakCompareAndSet(int expect, int update) {

   return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

}  

Note:同compareAndSet相比会错误的失败,并且不保证排序,表示不理解?

public final void lazySet(int newValue) {

  unsafe.putOrderedInt(this, valueOffset, newValue);

}

Note:putOrderedInt值是立即写回主存还是不立即写回主存,按顺序写回主存?

 

实现总结:AtomicInteger的功能实现比较简单,基本都是使用Unsafe的CAS无锁编程实现,首先获取到value值,然后进行计算后得到新值,最后使用CAS进行内存更新。此类有多处需要注意的地方:使用自旋实现内存更新,在设值和计算的时候有++i(Get在后面)和i++的区别,除了两数相加和自增以外没有提供其它的操作,可直接使用CAS来更新value值。