线程安全、线程同步、竞态条件

一、线程安全(Thread Safety)

定义:

当多个线程同时访问一个对象/数据时,不管操作系统怎么调度这些线程,也不管它们的执行顺序怎么穿插交织,最终的结果都必须是正确的,不会出现数据错乱、重复、丢失等问题。

核心就一句话:并发执行,结果仍对。

类比: 就像银行转账。你同时用手机APP和网页端各转一笔钱,银行系统必须保证:

  • 不会因为你两个渠道同时操作,就把你的钱算错

  • 不会转出去双倍的钱

  • 也不会吞掉你的钱

你的系统现在线程不安全,因为两个用户同时审核,生成了两张入库单------结果错了。


二、线程同步(Thread Synchronization)

定义:

协调多个线程对共享资源的访问顺序,让它们"有规矩"地执行,避免互相干扰、互相覆盖。

给共享资源加把锁,保证同一时刻只有一个线程可以访问他。

核心就一句话:给并发访问定规矩。

类比: 想象一个单向通行的隧道:

  • 没有同步:两辆车对头开,直接在隧道中间撞车(数据冲突)

  • 有同步:要么装红绿灯轮流走(互斥),要么分道行驶各走各的(隔离)

同步只是实现"线程安全"的一种手段,不是唯一手段。除了"排队访问"(同步),还可以通过"各用各的"(ThreadLocal)或"只读不写"(不可变对象)来实现安全。


三、竞态条件(Race Condition)

定义:

多个线程同时读写共享资源,最终的结果取决于它们执行的"先后顺序"和"时机"------就像赛跑,谁先谁后到终点,结果完全不同。

核心就一句话:结果看运气,取决于谁先执行完。


"检查-执行"模式:竞态条件的温床

在业务代码里,最常见的就是 "检查-然后-执行"(Check-Then-Act) 模式:

复制代码
// 第1步:检查条件
if (单据状态.equals("待审核")) {
    // 第2步:执行动作
    updateStatus("已审核");
    createStockInOrder();
}

单线程下,这段代码毫无问题。但多线程下,"检查"和"执行"是两个独立的操作,中间存在时间窗口。另一个线程完全可以趁这个空档插入进来,基于同样过期的检查结果也执行一遍。


你的审核Bug时间线

复制代码
时间点        用户A的线程                    用户B的线程                 数据库状态
─────────────────────────────────────────────────────────────────────────────────────
09:00:00.100  【检查】查询状态 → 待审核                                  待审核
09:00:00.150                                【检查】查询状态 → 待审核     待审核
              ↑                                                        ↑
              └────────── 两人都通过了"检查",都准备执行 ──────────────┘

09:00:00.200  【执行】更新为已审核,生成入库单①                          已审核
09:00:00.250                                【执行】更新为已审核,
                                            生成入库单②                 已审核
                                            ↑
                                            └─ B也执行了!因为B检查时状态还是"待审核"

同样的代码,同样的操作,只是因为线程执行的时机不同:

执行顺序 结果
A 完整做完(检查+执行)→ B 再做 ✅ 只生成一张入库单
A 检查完 → B 检查完 → A 执行 → B 执行 ❌ 生成两张入库单

一句话总结

竞态条件 = "检查-执行"模式在多线程下被并发打断,另一个线程基于过期的检查结果执行了动作,导致程序正确性取决于不可控的线程调度顺序。


四、三者之间的关系

复制代码
┌─────────────────────────────────────────────┐
│                                             │
│   竞态条件(Race Condition)                 │
│   ↓ 是问题的根源                             │
│   "多线程读写共享资源,时机不确定导致结果错乱"    │
│                                             │
│            ↓ 需要用手段解决                    │
│                                             │
│   线程同步(Thread Synchronization)         │
│   ↓ 是解决问题的手段                          │
│   "协调线程访问顺序,给并发定规矩"              │
│                                             │
│            ↓ 最终实现目标                      │
│                                             │
│   线程安全(Thread Safety)                  │
│   ↓ 是最终要达到的状态                        │
│   "不管怎么并发,结果始终正确"                 │
│                                             │
└─────────────────────────────────────────────┘

五、结合你的审核Bug串起来

概念 在你的系统里具体表现
竞态条件 用户A和用户B几乎同时查询单据状态,都查到"待审核",然后各自执行了审核逻辑
线程同步缺失 代码里"查询判断"和"更新状态"之间没有加锁或版本控制,两个线程穿插执行没人管
线程不安全 最终结果错误:同一张单据生成了两张入库单,数据库里状态虽然都是"已审核",但业务数据重复了

六、一句话记住三者

竞态条件 = "为什么会出事"(多线程抢资源,时机不可控)
线程同步 = "怎么防止出事"(给并发定规矩,排队或事后检查)
线程安全 = "出事了吗"(最终结果对不对,是目标也是检验标准)

你的Bug修复,本质上就是用线程同步的手段(悲观锁/乐观锁),消除竞态条件,最终实现线程安全

相关推荐
小小测试开发6 小时前
安装 Python 3.10+
开发语言·人工智能·python
AAA大运重卡何师傅(专跑国道)8 小时前
【无标题】
开发语言·c#
XBodhi.8 小时前
Visual Studio C++ 语法错误: 缺少“;”(在“return”的前面)
开发语言·c++·visual studio
LSssT.9 小时前
【01】Python 机器学习
开发语言·python
心之伊始9 小时前
Java 后端接入大模型:从 Token、并发到推理成本的完整估算方法
java·spring boot·性能优化·大模型·llm
l1t9 小时前
DeepSeek总结的使用实体-组件-系统和基于存在性处理进行Python编程39-40
开发语言·python
BlackTurn9 小时前
技术经理投标
java
曾阿伦9 小时前
Python 搭建简易HTTP服务
开发语言·python·http
YG亲测源码屋10 小时前
java配置环境变量、jdk环境变量配置、java环境变量设置方法
java·开发语言
MIUMIUKK10 小时前
从语法层面,看懂 Python 的特殊处
java·开发语言·python