Node.js中操作原子操作主要依赖SharedArrayBuffer和Atomics对象实现,这两个特性从Node.js 10版本开始正式支持,能够在多线程共享内存的场景下保证操作的原子性,避免数据竞争问题。

原子操作的基本概念
原子操作指的是不可被中断的一个或一组操作,在执行过程中不会被其他线程干扰,要么全部执行完成,要么完全不执行。在多线程场景下,多个线程同时修改同一块共享内存时,如果没有原子操作保证,很容易出现数据不一致的问题。比如两个线程同时对一个数值做加一操作,最终得到的结果可能不符合预期。
Node.js中原子操作的基础依赖
SharedArrayBuffer
SharedArrayBuffer是共享内存的缓冲区,多个Worker线程可以访问同一份SharedArrayBuffer实例,实现内存共享。普通的ArrayBuffer是每个线程独享的,无法实现共享内存场景下的数据交互。
Atomics对象
Atomics是一个内置对象,提供了一些静态方法,用来对SharedArrayBuffer进行原子级别的操作,所有方法都是原子性的,不会被其他线程打断。它支持的操作包括读写、加减、比较交换等。
Atomics常用方法说明
| 方法名 | 作用说明 |
|---|---|
| Atomics.load(typedArray, index) | 原子性地从typedArray的指定index位置读取数值 |
| Atomics.store(typedArray, index, value) | 原子性地将value写入typedArray的指定index位置 |
| Atomics.add(typedArray, index, value) | 原子性地将typedArray指定位置的数值加上value,返回加法前的值 |
| Atomics.sub(typedArray, index, value) | 原子性地将typedArray指定位置的数值减去value,返回减法前的值 |
| Atomics.compareExchange(typedArray, index, expectedValue, replacementValue) | 如果typedArray指定位置的当前值等于expectedValue,就原子性地替换为replacementValue,返回原来的值 |
| Atomics.wait(typedArray, index, value, timeout) | 如果typedArray指定位置的当前值等于value,就阻塞当前线程直到被唤醒或者超时,返回字符串表示状态 |
| Atomics.notify(typedArray, index, count) | 唤醒在typedArray指定位置等待的线程,最多唤醒count个,返回实际唤醒的数量 |
Node.js中原子操作示例
基础读写操作示例
下面的代码演示了如何使用Atomics进行原子性的读写操作:
// 创建长度为1的Int32Array,基于SharedArrayBuffer
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);
// 原子性写入数值10
Atomics.store(int32, 0, 10);
console.log('写入后的数值:', Atomics.load(int32, 0)); // 输出10
// 原子性加5
const oldValue = Atomics.add(int32, 0, 5);
console.log('加法前的值:', oldValue); // 输出10
console.log('加法后的数值:', Atomics.load(int32, 0)); // 输出15
// 原子性减3
Atomics.sub(int32, 0, 3);
console.log('减法后的数值:', Atomics.load(int32, 0)); // 输出12
多线程场景下的原子操作示例
下面的代码使用Worker线程模拟多线程场景,演示原子操作如何避免数据竞争:
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
if (isMainThread) {
// 主线程创建共享内存
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);
Atomics.store(int32, 0, 0);
// 创建两个工作线程
const worker1 = new Worker(__filename, { workerData: sab });
const worker2 = new Worker(__filename, { workerData: sab });
// 等待两个线程执行完成
let finished = 0;
const checkFinish = () => {
finished++;
if (finished === 2) {
// 最终数值应该是200,因为每个线程加100次,每次加1
console.log('最终共享内存的数值:', Atomics.load(int32, 0));
}
};
worker1.on('exit', checkFinish);
worker2.on('exit', checkFinish);
} else {
// 工作线程逻辑
const sab = workerData;
const int32 = new Int32Array(sab);
// 每个线程对共享数值加100次
for (let i = 0; i < 100; i++) {
// 原子性加1,避免数据竞争
Atomics.add(int32, 0, 1);
}
parentPort.postMessage('done');
}
注意事项
- Atomics的所有方法只能操作基于SharedArrayBuffer的TypedArray,比如Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array,不支持普通的数组或者Object。
- 使用SharedArrayBuffer需要Node.js运行在合适的环境下,部分旧版本或者特殊配置的环境可能不支持。
- Atomics.wait只能在主线程或者Worker线程中使用,不能在不可等待的上下文中调用,否则会报错。
- 原子操作虽然能保证操作的原子性,但是过多使用可能会导致性能开销,需要根据实际场景合理选择。
Node.js原子操作AtomicsSharedArrayBuffer多线程修改时间:2026-06-26 19:42:19