竞态条件本质是多线程对共享可变状态执行非原子操作时因执行顺序交错导致错误,解决关键在于保障原子性、可见性、有序性;需用同步机制保护临界区,优先选用synchronized代码块或reentrantlock,高并发低争抢场景可用原子类,最彻底方案是从设计源头规避共享可变状态,并辅以volatile保证可见性与禁止重排序。

竞态条件问题本质是多个线程对共享可变状态执行非原子操作时,因执行顺序交错导致结果错误。解决关键在于保障原子性、可见性、有序性,而不是笼统加锁或回避并发。
用同步机制保护临界区
当一段代码访问并修改共享变量时,必须确保同一时刻只有一个线程执行它。
- synchronized 方法:适用于简单场景,锁住当前实例(非静态)或类对象(静态方法),但粒度较粗,可能影响吞吐量
-
synchronized 代码块:只锁定真正需要保护的语句,例如
synchronized(sharedObj) { sharedObj.update(); },推荐优先使用 -
ReentrantLock:提供更灵活的控制,比如可中断等待、超时获取、公平策略;注意必须在
finally块中释放锁,避免死锁风险
用原子类替代普通变量
对单个变量的读-改-写操作(如计数器递增、标志位切换),优先选用 java.util.concurrent.atomic 包中的类型。
-
AtomicInteger、AtomicLong支持incrementAndGet()、compareAndSet()等原子方法 - 底层依赖 CPU 的 CAS 指令,无锁且性能高,适合高并发低争抢场景
- 不适用于复合逻辑(如“先判断再更新”需配合
compareAndSet循环重试)
从设计源头规避共享可变状态
最彻底的解法不是“怎么锁”,而是“为什么需要锁”。
- 用不可变对象(
final字段 + 无修改方法)传递数据,天然线程安全 - 采用线程局部存储(
ThreadLocal)为每个线程维护独立副本,适用于上下文信息(如用户身份、事务ID) - 改用无状态设计或消息传递模型(如 Actor 模式),让线程间不直接共享内存
配合 volatile 保证可见性与禁止重排序
volatile 不解决原子性,但能防止指令重排,并确保一个线程对变量的写立即对其他线程可见。
- 适合用作状态标志(如
running = false控制循环退出) - 不能用于
i++这类复合操作,因为读和写仍是分开的两步 - 与 synchronized 或原子类搭配使用,补全内存模型保障
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











