atomics.notify必须与atomics.wait配对使用且仅限worker线程,主线程调用报typeerror;需确保目标视图为int32array、索引有效,并在至少一个worker已挂起于该位置时调用,count参数表示最多唤醒数量而非次数。

Atomics.notify 不能单独触发“异步唤醒”——它必须和 Atomics.wait 配对使用,且只能在 Worker 线程中生效;主线程调用会直接报错,不配 wait 则 notify 完全无意义。
Atomics.notify 调用失败的典型错误现象
常见报错包括:TypeError: notify not allowed on main thread(主线程调用)、RangeError: view is not an Int32Array(传入了 Uint8Array 或 Float64Array)、RangeError: invalid index(索引越界)。这些都不是“唤醒失败”,而是根本没进入等待队列的前置校验失败。
更隐蔽的问题是:调用 Atomics.notify(view, 0, 1) 后,没有任何 Worker 被唤醒——原因通常是:目标 Worker 根本没在位置 0 上执行 Atomics.wait,或者它刚执行完 wait 就被调度切走了,还没来得及挂起。
- 必须确保
notify前,至少一个 Worker 已调用Atomics.wait(view, 0, expectedValue)并处于挂起状态 - 通知目标必须是
Int32Array视图,且索引在有效范围内(0 ) - 不要在主线程尝试调用
Atomics.notify—— 浏览器会立即抛出TypeError
高频唤醒场景下 notify 的参数陷阱
Atomics.notify(view, index, count) 的 count 参数不是“唤醒次数”,而是“最多唤醒 count 个正在该索引等待的线程”。它不排队、不缓冲、不重试:如果当前只有 1 个线程在等,传 100 和传 1 效果完全一样;如果没人等,调用直接返回 0,不会暂存通知。
- 高频唤醒时,避免用固定
count = 1逐个通知——若多个 Worker 同时在等,应设为足够大的值(如10),否则部分线程永远收不到 - 不要依赖
notify的返回值判断“是否成功唤醒”:返回0只说明当前无人等待,不代表逻辑出错 - 若需广播唤醒所有等待者,
count设为Infinity不合法,应设为一个明显大于可能并发数的整数(如100)
为什么 Atomics.wait + notify 不等于 setTimeout/setImmediate
Atomics.wait 是阻塞式挂起,它让 Worker 线程真正让出 CPU,不消耗任何计算资源;而 setTimeout 或轮询 Atomics.load 会持续占用线程、吃满 CPU。但这也意味着:一旦 wait 执行,线程就“消失”了,直到 notify 把它拉回来——中间无法插入任何逻辑,也无法中断。
- 不要在
wait前忘记检查条件:必须先确认当前值符合预期(如Atomics.load(view, 0) === 1),再调用wait(view, 0, 1),否则会立即返回"not-equal" - 没有超时机制:旧版
Atomics.wait不支持毫秒参数,传第四个参数会被忽略;如需防死锁,必须配合自旋+时间戳+重试逻辑 - ECMAScript 2024 新增了
Atomics.waitAsync,返回 Promise,可配合AbortSignal实现带超时的等待,但目前仅 Chrome 125+ 支持
跨线程高频唤醒的实际数据流结构
高频唤醒不是靠反复 notify,而是靠“状态位复用 + 批量数据区解耦”。例如:用 Int32Array 的第 0 位做控制信号(1 表示有新任务),第 1 位起存放任务参数;Worker 每次 wait 成功后,立刻读取参数区并重置信号位为 0,主线程则在写完参数后才 notify。
- 避免每次唤醒都传递大量数据:共享内存中只放指针或偏移,真实数据放在同一
SharedArrayBuffer的其他区域 - 信号位必须用
Atomics.compareExchange更新,防止多次 notify 被压缩成一次(比如两个主线程几乎同时写1,第二个会失败,但 notify 仍只发一次) - Worker 唤醒后第一件事是用
Atomics.compareExchange(view, 0, 1, 0)尝试清零信号——成功说明自己抢到了本次任务,失败则说明已被别的 Worker 处理,直接跳过
最易被忽略的一点:高频唤醒下,notify 的调用时机必须严格落在“数据已写稳、信号位已置位、且无竞态覆盖”的窗口内。这个窗口极小,靠手写 store + notify 两步极易出错,必须用 compareExchange 做原子化封装,或引入专用的锁区协调。











