一、一般情况下的单线程
JavaScript 在webworks和 Node.js 环境下,主线程通常是单线程执行的,这意味着同一时间只会执行一个任务,所以大部分情况下不需要传统意义上的互斥锁。
javascript">let counter = 0;function increment() {counter++;console.log(counter);
}function decrement() {counter--;console.log(counter);
}increment();
decrement();
在这个例子中,由于代码是按顺序依次执行的,不会出现多个任务同时修改 counter
变量的情况,所以不需要互斥锁来保证数据的一致性。
二、多线程
Web Workers 允许在浏览器中创建多个线程,这些线程可以并行执行 JavaScript 代码。当多个 Web Worker 同时访问和修改共享资源时,就需要互斥锁来避免数据竞争。
javascript">// main.js
const worker = new Worker('worker.js');
let sharedResource = 0;
let lock = false;function acquireLock() {while (lock) {// 等待锁释放}lock = true;
}function releaseLock() {lock = false;
}worker.onmessage = function (event) {acquireLock();sharedResource += event.data;console.log('Shared resource:', sharedResource);releaseLock();
};worker.postMessage(1);// worker.js
self.onmessage = function (event) {self.postMessage(2);
};
在这个示例中,acquireLock
和 releaseLock
函数模拟了互斥锁的功能,确保在一个线程访问 sharedResource
时,其他线程不能同时访问。
三、 Node.js 中的多进程或异步操作
在 Node.js 中,虽然主线程是单线程的,但可以使用 child_process
模块创建多个进程,或者使用异步操作处理并发任务。当多个进程或异步操作同时访问共享资源时,也需要互斥锁来保证数据的一致性。
javascript">const fs = require('fs');
const path = require('path');const lockFilePath = path.join(__dirname, 'lockfile');function acquireLock(callback) {fs.writeFile(lockFilePath, '', { flag: 'wx' }, (err) => {if (err) {if (err.code === 'EEXIST') {// 锁已被占用,等待一段时间后重试setTimeout(() => acquireLock(callback), 100);} else {callback(err);}} else {callback(null);}});
}function releaseLock(callback) {fs.unlink(lockFilePath, callback);
}acquireLock((err) => {if (err) {console.error('Failed to acquire lock:', err);return;}// 执行需要互斥访问的操作console.log('Lock acquired, performing operation...');releaseLock((err) => {if (err) {console.error('Failed to release lock:', err);} else {console.log('Lock released.');}});
});
在这个 Node.js 示例中,通过文件锁的方式实现了互斥锁的功能,确保同一时间只有一个进程可以执行需要互斥访问的操作。
综上所述,虽然 JavaScript 主线程是单线程的,但在多线程或异步并发场景下,为了保证数据的一致性和操作的正确性,可能需要使用互斥锁。
四、TS的互斥锁
1、简单写法
javascript">class Mutex {private isLocked: boolean = false;// 尝试获取锁,如果锁已被占用则等待async acquire(): Promise<void> {while (this.isLocked) {await new Promise(resolve => setTimeout(resolve, 10));}this.isLocked = true;}// 释放锁release(): void {this.isLocked = false;}
}// 使用示例
async function main() {const mutex = new Mutex();async function task(id: number) {await mutex.acquire();console.log(`Task ${id} acquired the lock`);// 模拟一些耗时操作await new Promise(resolve => setTimeout(resolve, 1000));console.log(`Task ${id} released the lock`);mutex.release();}// 同时启动多个任务Promise.all([task(1), task(2)]);
}main();
2、高阶写法:
javascript">/*** 互斥锁函数:确保前一个调用完成后才能接受新的调用* @param func 要被锁定的函数(支持同步 & 异步)* @returns 经过锁保护的函数*/export function mutexLock<T extends (...args: any[]) => any>(func: T
): (...funcArgs: Parameters<T>) => Promise<ReturnType<T> | void> {let isLocked = false;return async function (this: any,...args: Parameters<T>): Promise<ReturnType<T> | void> {if (isLocked) return; // 🚫 忽略请求(上一个仍在执行)isLocked = true; // 🔒 进行加锁try {return await func.apply(this, args); // ⏳ 执行原始函数} finally {isLocked = false; // 🔓 任务完成,解锁}};
}