什么是AtomicInteger

AtomicInteger 顾名思义是一个具有原子化操作的 Integer,与普通的Integer的区别是 AtomicInteger 采用一个CAS 的方式使Integer 的自增等操作变成原子化操作。

实现的之前需要了解的知识

首先我们先观察 AotmicInteger 的自增操作:

1
2
3
4
5
6
7
8
public final int incrementAndGet() {
         for (;;) {
          int current = get();
          int next = current + 1;
          if (compareAndSet(current, next))
             return next;
          }
 }

他采用了死循环,并且每次循环都获取最新的value,通过这个值计算出自增后的值,使用compareAndSet 来交换值,并且判断结果,如果是true 就返回自增后的值,如果是false就进行重试,其实这就是一个典型的CAS 操作。

并且这个 compareAndSet 操作,其实很简单,就是调用 unsafe 对象的 compareAndSwapInt

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

compareAndSwapInt 就是根据当前对象的所需要 CAS 操作的成员的所在对象的 offset 来进行 CAS 的修改操作。

然后我们来看一下 get() 方法:

1
2
3
4
5
private volatile int value;
public final int get() {
  return value;
}

就是返回 volatile 修饰的值,因为获取这个值是原子化行为,并且 volatile 能保证这个值是最新的。

我的实现

需要注意的是 Unsafe.getUnsafe 是无法直接调用的,因为他会判断是否是BootStap的类加载器或者是Ext类加载器,如果不是就抛出异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class AtomicInteger {
    private static final Unsafe unsafe = getUnsafeInstance();

    private static long offset;

    static {
        try {
            offset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }


    private volatile int value;

    AtomicInteger(int value) {
        this.value = value;
    }

    //通过反射获取对应实例
    private static Unsafe getUnsafeInstance() {
        Field unsafeInstance;
        try {
            unsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
            unsafeInstance.setAccessible(true);
            return (Unsafe) unsafeInstance.get(Unsafe.class);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    int incrementAndGet() {
        int curr;
        int next;
        do {
            curr = get();
            next = curr + 1;
        } while (!unsafe.compareAndSwapInt(this, offset, curr, next));

        return get();
    }

    public int get() {
        return value;
    }
}