`Integer` 和 `AtomicInteger` 都是 Java 中用于表示整数的类,但它们在设计目的、线程安全性和使用场景上有显著区别。
一、基本特性对比
| 特性 | Integer | AtomicInteger |
|---------------------|-----------------------------|-----------------------------|
| 包路径 | java.lang | java.util.concurrent.atomic |
| 可变性 | 不可变(immutable) | 可变(mutable) |
| 线程安全性 | 非线程安全 | 线程安全 |
| 原子操作支持 | 不支持 | 支持 |
| 适用场景 | 一般数值表示 | 并发环境下的计数器等 |
| 性能开销 | 低 | 略高(因CAS操作) |
二、核心区别详解
1. 可变性差异
Integer:
private final int value; // 使用final修饰,不可变 public Integer(int value) { this.value = value; }
- 一旦创建就不能修改其值
- 任何"修改"操作都会创建新对象
AtomicInteger:
private volatile int value; // 可变,使用volatile保证可见性 public AtomicInteger(int initialValue) { value = initialValue; }
- 可以直接修改内部值
- 提供`set()`、`get()`等方法直接操作值
2. 线程安全性
Integer:
- 基本操作非线程安全
- 多线程环境下需要额外同步
Integer count = 0; // 线程不安全,需要同步 synchronized(lock) { count = count + 1; // 自动装箱创建新对象 }
AtomicInteger:
- 内置线程安全保证
- 使用CAS(Compare-And-Swap)实现原子操作
AtomicInteger count = new AtomicInteger(0); // 线程安全操作 count.incrementAndGet(); // 原子性自增
3. 原子操作支持
AtomicInteger 提供丰富的原子操作方法:
- `getAndIncrement()`: i++
- `incrementAndGet()`: ++i
- `getAndDecrement()`: i--
- `decrementAndGet()`: --i
- `getAndAdd(int delta)`: 获取当前值并加上delta
- `addAndGet(int delta)`: 加上delta并返回新值
- `compareAndSet(int expect, int update)`: CAS操作
Integer 完全不支持这些操作,所有算术运算都会创建新对象。
三、底层实现原理
Integer
- 基于基本类型int的包装类
- 值存储在final字段中
- 自动装箱/拆箱机制
AtomicInteger
- 使用Unsafe类实现底层操作
- 依赖CAS指令(CPU级别原子操作)
- volatile保证可见性
- 典型CAS实现:
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); // 获取当前值 } while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS尝试更新 return v; }
四、使用场景对比
适合使用Integer的场景
1. 作为方法参数或返回值传递整数值
2. 集合中的元素存储
3. 不需要修改的配置值
4. 非并发环境下的简单计数
适合使用AtomicInteger的场景
1. 高并发环境下的计数器
// 统计请求次数 private AtomicInteger requestCount = new AtomicInteger(0); void handleRequest() { requestCount.incrementAndGet(); // ... }
2. 状态标志位
private AtomicInteger status = new AtomicInteger(0); void changeStatus() { status.compareAndSet(0, 1); // 只有当前是0时才改为1 }
3. 序列号生成器
private AtomicInteger seq = new AtomicInteger(0); int nextId() { return seq.getAndIncrement(); }
五、性能考虑
1. 单线程环境:
- Integer性能更好
- AtomicInteger有额外的CAS开销
2. 低竞争多线程环境:
- AtomicInteger表现良好
- 比synchronized的Integer效率高
3. 高竞争环境:
- AtomicInteger可能出现CAS失败重试
- 可能需要考虑LongAdder(JDK8+)
六、典型错误用法
错误1:误以为Integer的原子性
Integer count = 0; // 看似原子操作,实际是非原子的复合操作 count++; // 等效于: // int temp = count.intValue(); // temp = temp + 1; // count = Integer.valueOf(temp);
错误2:不必要的AtomicInteger使用
// 在单线程或不可变场景使用AtomicInteger是浪费 AtomicInteger id = new AtomicInteger(1); System.out.println(id.get()); // 简单读取使用Integer即可
七、扩展比较
与synchronized的比较
// 使用synchronized实现线程安全计数 private int count = 0; public synchronized void increment() { count++; } // 使用AtomicInteger实现 private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); }
- AtomicInteger在低竞争下性能更好
- synchronized在高竞争下可能更稳定
与volatile的比较
private volatile int count = 0; public void unsafeIncrement() { count++; // 虽然是volatile,但++操作不是原子的 }
- volatile只保证可见性,不保证原子性
- AtomicInteger同时保证可见性和原子性
八、总结
1. 不可变 vs 可变:Integer设计为不可变类,AtomicInteger是可变且线程安全的
2. 简单 vs 复杂:Integer用于简单值传递,AtomicInteger用于并发控制
3. 性能取舍:单线程用Integer,并发计数用AtomicInteger,超高并发考虑LongAdder
4. 底层机制:AtomicInteger基于CAS和volatile实现无锁线程安全
根据具体场景选择合适的类型:
- 需要在线程间共享和修改的计数器 → AtomicInteger
- 作为方法参数或集合元素 → Integer
- 超高并发统计 → 考虑LongAdder(JDK8+)
0条评论
点击登录参与评论