AtomicInteger 和 volatile Integer对比

发布于:2025-06-21 ⋅ 阅读:(15) ⋅ 点赞:(0)

AtomicIntegervolatile Integer 虽然都与线程安全有关,但本质完全不同。它们的主要区别体现在原子性保证和功能上:


🔍 核心区别对比表

特性 volatile Integer AtomicInteger
原子性 ❌ 不保证复合操作原子性 ✅ 保证所有操作的原子性
自增操作安全性 i++ 不安全 incrementAndGet() 安全
CAS 操作 ❌ 不支持 ✅ 原生支持 compareAndSet()
函数式更新 ❌ 不支持 ✅ 支持 updateAndGet()
性能表现 简单读写快 复合操作远优于锁同步
内部原理 内存屏障 + 禁止重排序 volatile + CAS 自旋

⚠️ volatile Integer 的问题演示

public class VolatileCounter {
    private volatile Integer count = 0;

    // 线程不安全的操作!
    public void increment() {
        count++; // 实际分为三步: 读 -> 改 -> 写
    }

    public int getCount() {
        return count;
    }
}

问题代码解释

  1. 当线程A读取 count=0
  2. 线程B同时读取 count=0
  3. 线程A计算 0+1=1 写入
  4. 线程B计算 0+1=1 写入
  5. 结果:实际执行了两次自增,值却只变为1

✅ AtomicInteger 解决方案

import java.util.concurrent.atomic.AtomicInteger;

public class SafeCounter {
    private final AtomicInteger count = new AtomicInteger(0);
    
    // 线程安全操作
    public void safeIncrement() {
        count.incrementAndGet(); // 原子操作
    }
    
    public int getCount() {
        return count.get();
    }
}

关键原理

// AtomicInteger 内部实现原理
public final int incrementAndGet() {
    return U.getAndAddInt(this, VALUE, 1) + 1;
}

// 实际执行(Unsafe类):
public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);  // 1. 读取volatile值
    } while (!weakCompareAndSetInt(v, v + delta)); // 2. CAS自旋
    return v;
}

📌 本质区别总结

  1. volatile 的作用

    • 只保证可见性有序性
    • 写操作立即刷新到主存
    • 读操作总是获取最新值
  2. AtomicInteger 的优势

    • 通过 volatile 变量 + CAS 自旋实现复合操作原子性
    • 内置支持数学运算、比较交换等功能
    • 封装了线程安全的无锁算法
  3. 性能对比场景

    // 测试代码片段
    for(int i=0; i<1000000; i++) {
         // volatile版:1000ms+ 
         // AtomicInteger版:200ms
    }
    

🔄 关系示意图

volatile int value (基本保障)
     │
     ▼
  +-----------------+
  | AtomicInteger    |→ CAS保证复合操作原子性
  |   (封装增强)     |→ 提供原子操作方法族
  +-----------------+

可见 AtomicInteger 内部使用 volatile 保证可见性(通过 private volatile int value 字段),但增加了 CAS 机制来实现更复杂的原子操作,这是单纯 volatile 做不到的。


💡 使用建议

  • 需要单一基本类型的原子操作 → 用 AtomicInteger/Long/Boolean
  • 需要简单可见性保证 → 用 volatile
  • 需要对象引用的原子更新 → 用 AtomicReference
  • JDK8+高并发计数场景 → 用 LongAdder

网站公告

今日签到

点亮在社区的每一天
去签到