简单来说:多线程要用锁,是因为多个线程同时访问“共享数据”时,会发生数据竞争,导致程序结果不可预测甚至崩溃。
下面从原因到本质逐步解释。
假设有两个线程同时做这件事:
int count = 0;
count++;
你以为流程是:
线程A:count = 0 → 1
线程B:count = 1 → 2
但实际上,count++ 并不是一步完成的,它至少包含三步:
如果两个线程交叉执行,可能会变成:
线程A:读到 count = 0
线程B:读到 count = 0
线程A:计算 0 + 1
线程B:计算 0 + 1
线程A:写回 1
线程B:写回 1
最终结果:只加了一次,但预期是两次。
这种问题就叫 竞态条件(Race Condition)。
只要满足下面三个条件,就可能需要锁:
✅ 只读:不需要锁
❌ 有写:必须考虑锁
锁的核心作用是 保证“临界区”的原子性和可见性。
保证一段代码 要么全部执行完,要么完全不执行,中间不会被其他线程打断。
保证一个线程对共享数据的修改,其他线程能立刻看到。
以 Java 为例:
synchronized (lock) {
count++;
}
执行逻辑变成:
这样就不会出现上面的“同时读到 0”的问题。
可能出现的问题包括:
而且这类 Bug 不可复现、难调试。
锁是最通用的方案,但不是唯一方案:
| 方案 | 适用场景 |
|---|---|
| 锁(synchronized / Lock) | 通用 |
| 原子类(AtomicInteger) | 简单计数 |
| 不可变对象 | 安全但受限 |
| 线程本地变量(ThreadLocal) | 不共享 |
| 无锁算法(CAS) | 高性能场景 |
多线程要用锁,是因为多个线程同时修改共享数据时,会导致数据竞争和不一致,锁用来保证同一时间只有一个线程进入关键代码区,从而保证程序的正确性。
如果你愿意,我可以用 C / C++ / Java / Python 的具体例子,或者画一张“时间线图”帮你更直观理解。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。