i++和++i在多线程下不安全,因属非原子的“读-改-写”操作,易致竞态条件;推荐用atomicinteger的incrementandget()或getandincrement(),或synchronized、reentrantlock保障线程安全。

i++ 和 ++i 在多线程环境下都不是线程安全的,因为它们本质上是“读取-修改-写入”三步组成的非原子操作。多个线程可能同时读到相同值,各自加1后再写回,最终只生效一次,造成结果丢失。
为什么自增不安全?
以 int i = 0 为例,两个线程同时执行 i++,可能发生:
- 线程A读取 i = 0
- 线程B也读取 i = 0
- A计算 0+1=1,写回 i = 1
- B计算 0+1=1,写回 i = 1(覆盖A的结果)
两次自增只让 i 变成 1,而非预期的 2。这种竞态条件在高并发下必然出现,且每次运行结果都可能不同。
用 AtomicInteger 替代普通 int
这是最常用、推荐的方案:用 java.util.concurrent.atomic.AtomicInteger 封装计数器,调用其原子方法。
- incrementAndGet():先自增再返回新值(等价于 ++i)
- getAndIncrement():先返回原值再自增(等价于 i++)
- 底层基于 CPU 的 CAS 指令,无锁、高效、不会死锁
示例:AtomicInteger count = new AtomicInteger(0); count.incrementAndGet();
用 synchronized 控制临界区
适用于需要保证一段逻辑整体原子性,或涉及多个变量协同更新的场景(比如转账:扣A账户 + 加B账户)。
- 修饰方法:public synchronized void increment() { count++; }
- 修饰代码块:synchronized(this) { count++; }(注意锁对象需一致)
- 静态共享变量建议用 synchronized(Counter.class) 或静态锁对象
优点是语义清晰、支持复杂逻辑;缺点是存在锁开销,粒度太大会影响并发性能。
用 ReentrantLock 显式加锁
比 synchronized 更灵活,适合需要可中断、超时或公平策略的场景。
- 必须在 finally 块中调用 unlock(),否则会永久阻塞其他线程
- 支持 tryLock(long timeout, TimeUnit unit),避免无限等待
- 默认非公平模式,性能接近 synchronized;开启公平锁会明显降低吞吐量
示例:lock.lock(); try { count++; } finally { lock.unlock(); }
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











