> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/programming-language/java/bing-fa-bian-cheng/juc-atomicxxx.md).

# JUC: AtomicXXX

### 使用

JDK在 `java.util.concurrent.atomic` 下提供了一系列AtomicXX类型，这些类型提供了一系列原子方法，可以避免线程安全问题。下面是AtomicInteger的使用方式：

```java
AtomicInteger i = new AtomicInteger(10);
i.incrementAndGet(); // 多个线程同时增加，不会造成线程安全问题
```

### 原理

Atomic类型皆是使用CAS（CompareAndSwap）来实现的。在java中，compareAndSwap也是一个方法，位于UnSafe类中：

```java
// AtomicInteger#incrementAndGet
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1; // 给对象this的valueOffset属性+1
}
```

```java
// UnSafe#getAndAddInt
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2); // 获取对象最新的值
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); // 如果不是期望值（var5仍是当前值，说明没有被其他线程修改），返回false，如果是期望值则设置为 var5+1 目标值

        return var5;
    }
```

```java
// UnSafe#compareAndSet 是一个native方法，如下是他的定义：
// obj ：包含要修改field的对象
// offset: obj中整型field的偏移量
// expect: 期待field中存在的值
// update: 如果期待成功，所要更新的新值
public final native boolean compareAndSwapInt(Object obj, long offset, int expect , int update);
```

CAS需要CPU原语支持，也称为无锁优化，自旋锁。

### ABA问题

使用CAS进行无锁优化时，有可能引发ABA问题：

```
假设现T1线程对变量A进行修改，获取期望值值为1
此时在A未进行CAS操作前，线程T2对变量A已经进行了一系列操作：将变量A变为了2，然后又变为了1
这时线程T1执行CAS操作，期望值为1，目标值也为1，对于T1来说，A是没变的，但是变量A确实已经发生改变了。
```

> 变量A不见得是数值，也有可能是对象。对象引用虽然不变，但是成员变量可能已经发生变化。

通俗点说就是，你的前女友在和你复合之后，看似和以前没有区别，但是其实已经经历了n个男人，这就是ABA问题。ABA问题针对简单数字增减一般是不会出现问题，是允许的；但是针对其他对象操作，就有可能发生问题。

#### 解决ABA问题

解决ABA问题最容易想到的办法就是给变量增加版本号，JDK已经了类 `AtomicStampedReference` 类解决ABA问题：

```java
// stamp：版本号，比如类似的单词timestamp
AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<Integer>(100, 0);

// 除了比较期望值与目标值，还要比较版本号
// 加一操作
atomicStampedRef.compareAndSet(100, 101, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
// 减一操作
atomicStampedRef.compareAndSet(101, 100, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
```

### LongAdder

此外，在 `java.util.concurrent.atomic` 下还包含XXXAdder类，以LongAdder为例：

```java
LongAdder longAdder = new LongAdder();
longAdder.add(100);
longAdder.increment();
```

LongAdder采用分段锁，这使得LongAdder的效率高于synchronized、Atomic。
