# 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。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/programming-language/java/bing-fa-bian-cheng/juc-atomicxxx.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
