atomics.wait 配合 sharedarraybuffer 实现 worker 间高效阻塞同步,需满足 coop/coep 响应头、crossorigin 加载、非 file:// 协议;主线程初始化 sharedarraybuffer 并 transfer 发送,worker 重建一致视图;加锁须循环校验+compareexchange,释放锁用 store+notify(, ,1) 精准唤醒。

要用 Atomics.wait 配合 SharedArrayBuffer 实现 Worker 间高效阻塞同步,关键不是“让线程停一会儿”,而是构建一个**条件驱动、可唤醒、防虚假触发**的协作机制。它只在 Worker 中有效,主线程调用会直接报错。
必须满足的运行环境前提
缺一不可,否则连 SharedArrayBuffer 实例都创建不了:
- 服务端响应头包含
Cross-Origin-Opener-Policy: same-origin和Cross-Origin-Embedder-Policy: require-corp - 所有脚本(包括 Worker 文件)加载时带
crossorigin属性,例如<script crossorigin src="worker.js"></script> - 不能用
file://协议打开页面,必须通过localhost或域名访问(如npx serve或python3 -m http.server)
共享内存与锁状态的初始化方式
主线程负责分配并分发,所有 Worker 必须使用完全一致的视图访问同一块内存:
- 主线程创建
new SharedArrayBuffer(4),再用new Int32Array(sab)封装为整数视图 - 将首元素设为初始状态:
Atomics.store(view, 0, 0)(0 表示空闲) - 通过
worker.postMessage(sab, [sab])发送 —— 注意[sab]是 transfer list,不写就传副本,失去共享意义 - 每个 Worker 收到后,必须用相同构造方式重建视图:
const view = new Int32Array(e.data)
Worker 中安全等待与加锁的标准流程
Atomics.wait 不是单次判断,必须放在循环里,每次唤醒后重新校验条件是否真正成立:
- 先用
Atomics.load(view, 0) === 0检查当前是否空闲;不满足就进入等待 - 调用
Atomics.wait(view, 0, 0, 1e5):在索引 0 处等待值变为非 0,超时设为 100 秒防卡死 - 若返回
"ok",不代表已加锁,要再次Atomics.load(view, 0) === 0确认,再执行Atomics.compareExchange(view, 0, 0, 1)尝试原子占锁 - 只有
compareExchange返回0,才表示抢锁成功,可以执行临界区逻辑
释放锁并唤醒下一个等待者的正确姿势
释放动作必须原子、及时,且通知要精准,避免唤醒遗漏或误唤醒:
- 临界区结束后,先用
Atomics.store(view, 0, 0)清空锁状态 - 紧接着调用
Atomics.notify(view, 0, 1)—— 第三个参数填1表示只唤醒一个等待者,实现 FIFO 排队 - 不要用
Atomics.add(view, 0, -1)或其他非 store 操作清锁,语义不清且易出错 - 禁止在同一个位置混用不同视图类型(比如主线程用
Int32Array,Worker 用Uint8Array),会导致字节偏移错乱











