前言
异步锁是一种用于控制并发访问的锁机制,主要用于多线程/多任务环境下。异步锁允许多个任务并行执行,但是只允许一个任务在同一时间获取锁并执行临界区代码,其他任务需要等待该锁释放后才能获取锁并执行自己的临界区代码。
异步锁实现了互斥访问的机制,确保了同一时间只有一个任务可以访问共享资源。当一个任务获取了锁并执行临界区代码时,其他任务需要等待,直到锁被释放才能获取锁并执行自己的临界区代码。
异步锁的实现可以基于各种机制,如互斥量、信号量等。在使用异步锁时,需要注意避免死锁和活锁等并发访问问题,以确保程序的正确性和性能。
在许多编程语言和框架中,都提供了异步锁的内置支持或相关的库/工具,如Java的ReentrantLock、Python的asyncio.Lock等,开发者可以根据具体需求选择合适的异步锁实现。
一、js实现
编写lockUtils.js工具类
//简易异步锁对象,将异步任务变为并行运行
export class AsyncLock {
constructor() {
this.queue = [];
this.isLocked = false;
this.version = '0'
}
/**
* 获取锁
* @param {*} expire 锁过期时间
*/
async lock(expire) {
// 如果锁已被占用,则将当前任务加入等待队列
if (this.isLocked) {
if (this.queue.length < 10) {
await new Promise(resolve => this.queue.push(resolve));
}else{
return false
}
}
this.isLocked = true;
//生成锁版本号
let version = generateUUId()
this.version = version
//如果300毫秒后没有主动释放锁,则自动释放
if(!expire){
expire = 300
}
setTimeout(() => {
if (version == this.version && this.isLocked) {
console.log("自动释放锁------------------")
this.unlock();
}
}, expire);
return true;
}
unlock() {
// 如果有等待的任务,则从队列中取出一个并执行
if (this.queue.length > 0) {
const resolve = this.queue.shift();
resolve();
} else {
this.isLocked = false;
}
}
// 使用async函数包装锁的获取与释放,以简化外部使用
async withLock(task) {
let locked = await this.lock();
if(locked){
try {
return await task();
} finally {
this.unlock();
}
}
return locked
}
}
function generateUUId(){
let d = new Date().getTime(); // 获取当前时间戳
/* if (window.performance && typeof window.performance.now === "function") {
d += performance.now(); // 使用high resolution timestamp if available
} */
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid
}
二,使用
在异步方法中使用
let async = new AsyncLock()
async function test(){
let lock = await async.lock()
if (lock) {
console.log('执行任务')
}else {
console.log('获取锁失败')
}
async.unlock()
}
获取不到锁会先添加道队列当中等待,如果队列满,或者则获取锁失败
总结
获取不到锁会先添加道队列当中等待,如果队列满,或者则获取锁失败。
并且可以设置锁超时时间,超过时间自动释放锁