Bootstrap

js实现一个异步锁,超时自动释放,队列等待


前言

异步锁是一种用于控制并发访问的锁机制,主要用于多线程/多任务环境下。异步锁允许多个任务并行执行,但是只允许一个任务在同一时间获取锁并执行临界区代码,其他任务需要等待该锁释放后才能获取锁并执行自己的临界区代码。

异步锁实现了互斥访问的机制,确保了同一时间只有一个任务可以访问共享资源。当一个任务获取了锁并执行临界区代码时,其他任务需要等待,直到锁被释放才能获取锁并执行自己的临界区代码。

异步锁的实现可以基于各种机制,如互斥量、信号量等。在使用异步锁时,需要注意避免死锁和活锁等并发访问问题,以确保程序的正确性和性能。

在许多编程语言和框架中,都提供了异步锁的内置支持或相关的库/工具,如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()
}

获取不到锁会先添加道队列当中等待,如果队列满,或者则获取锁失败

总结

获取不到锁会先添加道队列当中等待,如果队列满,或者则获取锁失败。
并且可以设置锁超时时间,超过时间自动释放锁

;