javascript web worker 通过 sharedarraybuffer 实现共享内存,核心做法是在主线程创建 sharedarraybuffer 实例后,将其作为消息直接传递给 worker,或者在 worker 中接收并解析。由于安全限制,启用此功能需要服务器响应头包含 cross-origin-opener-policy: same-origin 和 security-policy: cross-origin-isolated(或等效的 coop/coep 设置),否则 atomics 操作会抛出异常。

如何正确初始化 SharedArrayBuffer 并传递数据
在主线程中,你需要实例化一个 SharedArrayBuffer 对象,指定所需的字节长度,然后通过 postMessage 方法将其发送给 Worker。关键在于必须使用 transferable objects 机制,即把 SharedArrayBuffer 放入 postMessage 的第二个参数数组中,这样内存所有权会转移给 Worker,而不是被复制。Worker 端接收到消息后,可以通过 e.data 获取该缓冲区实例,随后即可使用 Atomics 对象进行原子读写操作。

// main.js
const buffer = new SharedArrayBuffer(1024);
const worker = new Worker('worker.js');
worker.postMessage(buffer, [buffer]);
// worker.js
self.onmessage = function(e) {
const buffer = e.data;
// 现在可以在这里使用 Atomics 操作 buffer
Atomics.store(new Int32Array(buffer), 0, 42);
};
上述代码展示了最基础的传递方式。主线程创建了一个 1024 字节的缓冲区,并通过 [buffer] 告知浏览器这是一个可转移对象。Worker 收到后,e.data 就是那个唯一的内存块。此时,你可以将 buffer 包装成 Int32Array 或其他视图类型,以便以特定数据类型访问内存。这种传递方式是零拷贝的,性能极高,适合大数据量交换。
如何使用 Atomics 进行安全的并发读写
一旦 Worker 拥有了 SharedArrayBuffer 的引用,就可以使用全局 Atomics 对象来执行原子操作。这些操作保证了在多核并行环境下,对同一内存地址的读写不会被中断,从而避免竞态条件。常用的方法包括 Atomics.store、Atomics.load、Atomics.add 和 Atomics.wait。需要注意的是,所有 Atomics 方法都需要传入一个 SharedArrayBuffer 和一个索引值,通常我们会先创建一个 TypedArray 视图来简化调用。

// worker.js (continued) const int32View = new Int32Array(buffer); // 原子写入 Atomics.store(int32View, 0, 100); // 原子读取 const value = Atomics.load(int32View, 0); // 原子加法 Atomics.add(int32View, 0, 50); // 结果变为 150 // 等待某个位置的值变为预期值(阻塞当前线程) Atomics.wait(int32View, 0, 150); // 如果值不是 150,则挂起
在实际开发中,Atomics.wait 和 Atomics.notify 是实现高效同步的关键。Worker 可以调用 wait 挂起自身,直到主线程或其他 Worker 修改了指定位置的数值并调用 notify 唤醒它。这种方式比轮询(Polling)更高效,能显著降低 CPU 占用率。例如,主线程处理完数据后,更新缓冲区中的状态码并调用 Atomics.notify,通知正在等待的 Worker 继续处理下一批任务。
为什么我的 SharedArrayBuffer 操作会报错?
如果在尝试使用 SharedArrayBuffer 或 Atomics 时遇到 Synchronous HTTP request is not allowed 或 Atomics operations are not supported 等错误,根本原因通常是页面没有满足跨域隔离(Cross-Origin Isolated)的安全要求。现代浏览器出于防止 Spectre 等侧信道攻击的考虑,默认禁止非隔离页面使用共享内存。要解决这个问题,Web 服务器必须返回特定的 HTTP 响应头。
具体来说,服务器需要在所有 HTML 文档的响应中添加以下两个头部:
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp
COOP: same-origin 确保页面处于独立的浏览上下文组中,防止其他来源的 iframe 干扰。COEP: require-corp 则强制页面只加载经过明确授权的资源(如图片、脚本等),防止资源泄露。只有当这两个头部都存在且配置正确时,浏览器才会允许 JavaScript 创建 SharedArrayBuffer 并执行原子操作。在本地开发环境中,可以使用支持自定义响应头的代理工具或服务器中间件来模拟这些头部,以便进行测试。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











