Atomics.wait()和Atomics.notify()是条件等待原语,非互斥锁;需配合SharedArrayBuffer与跨源隔离使用,调用前必须用Atomics.load()检查值,否则可能因初始状态不满足而立即返回。

Atomics.wait() 和 Atomics.notify() 不能直接当“锁”用
它们是条件等待原语,不是互斥锁。你没法靠 Atomics.wait() “加锁”,也没法靠 Atomics.notify() “解锁”。强行模拟会出竞态:比如两个 Worker 同时发现“没人占着”,都跳过等待直接执行,就破坏了排他性。
真正能构建同步锁的原子操作是 Atomics.compareExchange(),配合循环重试实现 CAS(Compare-And-Swap)语义。而 wait()/notify() 的作用是:让空闲 Worker 睡着等通知,而不是轮询消耗 CPU。
- 必须搭配
SharedArrayBuffer使用,且页面需启用跨源隔离(COOP/COEP) - 等待前必须先用
Atomics.load()检查当前值,否则可能错过状态变更 -
Atomics.wait()会阻塞当前 Worker 线程(不是主线程),直到被notify()唤醒或超时 - 超时参数单位是毫秒,传
0表示不等待,只做一次检查;传Infinity不合法,会报错
为什么 wait() 前必须 load()?
这是最容易漏掉也最致命的一步。假设你期望等待位置 0 的值从 0 变为非零,但没先读一次:
Atomics.wait(view, 0, 0, 5000); // ❌ 错误:没确认初始值是否已是非零
如果主线程刚初始化完就把值设成了 1,这个 wait() 就会立刻返回 "timed-out" —— 它根本没等到“变化”,只是发现“当前就不满足等待条件”。
正确写法是显式确认:
if (Atomics.load(view, 0) === 0) {<br> const result = Atomics.wait(view, 0, 0, 5000);<br> if (result === "not-equal") { /* 值已变,可继续 */ }<br>}
-
Atomics.wait()只在值“等于预期”时才挂起;一旦不等,立即返回"not-equal" - 这个检查必须在调用
wait()前完成,且中间不能有其他线程修改该位置 - 若需严格顺序(如 A 完成后唤醒 B),建议用两个独立位置:一个表示状态,一个用于通知
notify() 唤不醒 wait() 的常见原因
现象是 Worker 一直卡在 Atomics.wait(),控制台无报错,但逻辑停住。大概率是下面某条没对上:
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
- 通知方和等待方用的不是同一个
Int32Array视图(比如类型不同:Uint32ArrayvsInt32Array,或偏移不同) -
Atomics.notify()调用位置(第二个参数)和wait()的位置不一致 - 通知发生在
wait()调用之前(即“先喊后等人”),此时无监听者,消息丢失 - 调用
notify()时,目标位置的值已经不是wait()期待的“旧值”了(比如被别的 Worker 改过) - 传给
notify()的第三个参数(唤醒数量)为0,等于没通知
调试建议:在 notify 前加一句 console.log(Atomics.load(view, 0)),确认值确实是你以为的“旧值”;并在 wait 前打日志记录进入等待的时间点。
高性能同步的关键不是“快”,而是“不忙等”
很多人想用 Atomics.wait() 替代 postMessage 来省掉序列化开销,但忽略了它的适用边界:它只适合“状态极简、变更稀疏、等待时间较长”的场景,比如任务队列空闲时休眠,或等待某个计算结果就绪。
如果你的 Worker 需要高频交互(比如每毫秒都要同步一次),wait()/notify() 反而更重——每次唤醒都涉及内核调度切换。这时不如用 Atomics.load() + 短间隔轮询(如 setTimeout(..., 1)),或者直接走 postMessage。
- 每个
wait()调用都会注册一个底层 futex 等待,大量并发等待可能耗尽系统资源 -
notify()是广播机制,无法指定唤醒哪个 Worker;如需定向唤醒,得自己维护等待者 ID 列表 - 没有超时保护的
wait()可能永久挂起,务必用Promise.race([Atomics.wait(...), timeoutPromise])
真正难的从来不是怎么写那几行原子操作,而是判断“这里到底该不该用 wait/notify”——多数时候,老实用 postMessage 更稳、更易 debug、也更容易横向扩展。










