i++ 不是线程安全的操作。这个问题涉及 Java 内存模型、原子性操作、线程同步等核心概念,让我们通过一个银行账户的故事来理解:
假设银行金库有 100 元现金,两个柜员(线程)同时执行以下操作:
public void withdraw() {
if(balance > 0) { // 1. 读取余额
balance--; // 2. 修改余额
}
}
i++ 在 JVM 中实际执行三个操作:
int temp = i; // 1. 读取主内存的值到工作内存
temp = temp + 1; // 2. 在工作内存执行计算
i = temp; // 3. 写回主内存
public synchronized void safeIncrement() {
i++;
}
特点:像银行金库的大门锁,同一时间只允许一个柜员操作
AtomicInteger atomicInt = new AtomicInteger(0);
atomicInt.getAndIncrement();
原理:通过 CAS (Compare-And-Swap) 实现无锁并发
Lock lock = new ReentrantLock();
public void safeIncrement() {
lock.lock();
try {
i++;
} finally {
lock.unlock();
}
}
优势:比 synchronized 更灵活,可设置超时、中断等
volatile int i = 0;
// 仍然不安全!
局限:只能保证可见性,无法保证原子性
方案 | 吞吐量 | 等待时间 | 适用场景 |
---|---|---|---|
synchronized | 低 | 长 | 简单同步需求 |
AtomicInteger | 高 | 无 | 计数器等高频操作 |
Lock | 中 | 可调控 | 复杂同步控制 |
volatile | 高 | 无 | 状态标志位 |
i++ 在并发环境下存在安全隐患,必须通过同步机制或原子类确保线程安全。选择方案时应根据具体场景权衡性能与复杂度,就像为不同规模的银行选择不同级别的安保系统。