【Java-多线程】i++ 是线程安全的吗?

i++ 不是线程安全的操作。这个问题涉及 Java 内存模型、原子性操作、线程同步等核心概念,让我们通过一个银行账户的故事来理解:


故事场景:银行金库争夺战

假设银行金库有 100 元现金,两个柜员(线程)同时执行以下操作:

public void withdraw() {
    if(balance > 0) {      // 1. 读取余额
        balance--;         // 2. 修改余额
    }
}
灾难现场(线程不安全)
  • 线程A 读取余额 100
  • 线程B 同时读取余额 100
  • 线程A 扣减为 99
  • 线程B 也扣减为 99
  • 结果:实际支取 2 元,余额却显示 99 元

根本原因分析

i++ 在 JVM 中实际执行三个操作:

int temp = i;    // 1. 读取主内存的值到工作内存
temp = temp + 1; // 2. 在工作内存执行计算
i = temp;        // 3. 写回主内存
线程不安全的三宗罪
  1. 非原子性:三个操作可能被线程切换打断
  2. 内存可见性:修改后的值可能未及时刷新到主内存
  3. 指令重排序:编译器优化可能改变指令顺序

️ 四种防御方案

方案1:synchronized 金库大锁
public synchronized void safeIncrement() {
    i++;
}

特点:像银行金库的大门锁,同一时间只允许一个柜员操作

方案2:AtomicInteger 智能保险箱
AtomicInteger atomicInt = new AtomicInteger(0);
atomicInt.getAndIncrement();

原理:通过 CAS (Compare-And-Swap) 实现无锁并发

方案3:Lock 定制密码锁
Lock lock = new ReentrantLock();
public void safeIncrement() {
    lock.lock();
    try {
        i++;
    } finally {
        lock.unlock();
    }
}

优势:比 synchronized 更灵活,可设置超时、中断等

方案4:Volatile 透明玻璃(不适用)
volatile int i = 0;
// 仍然不安全!

局限:只能保证可见性,无法保证原子性


性能对比表

方案 吞吐量 等待时间 适用场景
synchronized 简单同步需求
AtomicInteger 计数器等高频操作
Lock 可调控 复杂同步控制
volatile 状态标志位

思维导图总结

【Java-多线程】i++ 是线程安全的吗?_第1张图片


最终结论

i++ 在并发环境下存在安全隐患,必须通过同步机制或原子类确保线程安全。选择方案时应根据具体场景权衡性能与复杂度,就像为不同规模的银行选择不同级别的安保系统。

你可能感兴趣的:(大白话说Java,java,安全,开发语言)