去年有几个项目需要使用JavaScript互斥锁,所以写了几个类似的,这是其中一个:

//Published by Indream Luo
//Contact: indreamluo@qq.com
//Version: Chinese 1.0.0 !function ($) {
window.indream = window.indream || {};
$.indream = indream; indream.async = {
//
//锁
//lock: 锁的编号
//action: 解锁后执行的方法
//
lock: function (lock, action) {
$.indream.async.waitings[lock] = $.indream.async.waitings[lock] || [];
$.indream.async.waitings[lock].push(action);
//如果该锁未被使用,则当前action阻塞该锁
if (!$.indream.async.lockStatus[lock] && action) {
$.indream.async.lockStatus[lock] = true;
if (arguments.length > 2) {
var args = 'arguments[2]';
for (var i = 3; i < arguments.length; i++) {
args += ', arguments[' + i + ']';
}
eval('$.indream.async.action.call(action, ' + args + ')');
} else {
$.indream.async.action.call(action);
}
}
},
//
//解锁
//lock: 锁的编号
//
releaseLock: function (lock) {
$.indream.async.waitings[lock].shift();
//如果等待队列有对象,则执行等待队列,否则解锁
if ($.indream.async.waitings[lock].length) {
$.indream.async.waitings[lock][0]();
} else {
$.indream.async.lockStatus[lock] = false;
}
},
//
//锁的状态
//
lockStatus: [],
//
//等待事件完成
//lock:锁编码,相同的编码将被整合成一个序列,触发时同时触发
//
wait: function (lock, action) {
$.indream.async.waitings[code] = $.indream.async.waitings[code] || [];
$.indream.async.waitings[code].push(action);
},
//
//等待序列
//
waitings: [],
//
//数据缓存
//
action: {
//
//监听和回调的相关方法
//
callback: {
//
//监听
//
listen: function (actionName, callback) {
var list = $.indream.async.action.callback.list;
list[actionName] = list[actionName] || [];
list[actionName].push(callback);
},
//
//回调
//
call: function (actionName, args) {
var list = $.indream.async.action.callback.list;
if (list[actionName] && list[actionName].length) {
for (var i in list[actionName]) {
$.indream.async.action.call(list[actionName][i], args);
}
}
},
//
//现有的回调列表
//
list: []
},
//
//根据方法是否存在和参数是否存在选择适当的执行方式
//
call: function (action) {
if (action) {
if (arguments.length > 1) {
var args = 'arguments[1]';
for (var i = 2; i < arguments.length; i++) {
args += ', arguments[' + i + ']';
}
eval('action(' + args + ')');
} else {
action();
}
}
}
}
}
}(window.jQuery);

一个互斥锁的几个元素是:

  • 锁与解锁
  • 等待队列
  • 执行方法

以上锁的用法:

//定义锁的名称
var lock = 'scrollTop()';
//使用锁
$.indream.async.lock(lock, function () {
var scrollTop = $(window).scrollTop();
var timer;
var fullTime = 100;
for (timer = 0; timer <= fullTime; timer += 10) {
setTimeout('$(window).scrollTop(' + (scrollTop * (fullTime - timer) / fullTime) + ');', timer);
}
//释放锁
setTimeout('$.indream.async.releaseLock("' + lock + '");', fullTime);
});

关于这次所的实现,简单说明下。

-自旋锁还是信号量

JavaScript本身没有锁的功能,所以做的锁都是在高层实现的。

依据JavaScript单线程的原理,JS的线程资源十分有限,非常不适合使用自旋锁,所以选择了使用信号量。

自旋锁实现起来的样子大致是这样的,当然do while更多用了:

while(true) {
//do something...
}

这样必然需要占满线程资源,可惜JS只有一条线程可以用来执行,所以这样做十分不适用。当然,有需要可以选择setInterval和clearInterval的组合去实现,效果也会不错。

这里选用了信号量的方式,原理也简单,就如代码那么短。工作的执行顺序大致是:

  • 把代码段(回调的action)推入等待队列
  • 判断当前锁是否被持有,如果被持有则等待释放,否则获取该锁,执行回调
  • 当锁被释放,则在等待队列中shift出下一个回调,将锁传递给它并执行

-自动释放还是手动释放

看起来最舒服的方式当然是锁住之后当当前程序执行完就自动释放,不过这样并不容易,因为有更多的情况需要自定义释放场景。

本身使用锁的就是在异步中的方法,所以各种通常也会出现其他异步内容,比如AJAX、jQuery动画。这个时候,自动释放就不符合需求了,因为实际上真正的“执行完毕”是在它内部的异步回调完成后,也就是基本上只有开发人员自己能把握,所以这里选择了手释放。

不过还是有缺陷的,就是重复释放。

可以看到所有的锁的对象都是公有的,或者应该说JS所有对象都是公有的,除非使局部变量在访问级别上进行隔离。不过这里“锁”本身就是个公共资源,所以没办法处理。

这里可以做的优化应该是像setInterval和clearInterval的那样,以公共的锁名称进行加锁,以私有的锁ID进行解锁,就可以防止重复释放了。不过上面这段老代码中没有,估计很快就会用到的了。

简单的JavaScript互斥锁的更多相关文章

  1. JavaScript互斥锁案例

    朋友今天问起来关于JS中多个函数共享同一个全局变量时,顺序调用执行的函数,前者修改了全局变量值,后调用的函数访问时却为undefined. 前不久开发项目过程中,队友也遇到了同样的问题,索性就写份博客 ...

  2. 【多线程】C++ 互斥锁(mutex)的简单原理分析

    多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序.一般情况下,分为两种类型的多任务处理:基于进程和基于线程. 1)基于进程的多任务处理是程序的并发执行. 2)基于线程 ...

  3. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  4. 如何创建一个简单的C++同步锁框架(译)

    翻译自codeproject上面的一篇文章,题目是:如何创建一个简单的c++同步锁框架 目录 介绍 背景 临界区 & 互斥 & 信号 临界区 互斥 信号 更多信息 建立锁框架的目的 B ...

  5. Linux线程-互斥锁pthread_mutex_t

    在线程实际运行过程中,我们经常需要多个线程保持同步.这时可以用互斥锁来完成任务:互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthrea ...

  6. JUC回顾之-可重入的互斥锁ReentrantLock

    1.什么是可重锁ReentrantLock? 就是支持重新进入的锁,表示该锁能够支持一个线程对资源的重复加锁. 2.ReentrantLock分为公平锁和非公平锁:区别是在于获取锁的机制上是否公平. ...

  7. 互斥锁pthread_mutex_t的使用(转载)

    1. 互斥锁创建        有两种方法创建互斥锁,静态方式和动态方式.POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下: pthread_mut ...

  8. Java使用FileLock实现Java进程互斥锁

    原理:JDK的nio包中FileLock实现类似Linux fcntl的文件锁, 可使文件被进程互斥访问.  借助此功能, 可以实现强大的Java进程互斥锁, 从而在应用层面保证同一时间只有惟一的Ja ...

  9. win32进阶必备:多线程同步之互斥锁

    应用多线程互斥锁之前首先简单过一下C程序可能用到的3个创建线程函数: CreateThread,windows系统提供的唯一创建线程API,_beginthread和_beginthreadex都在内 ...

随机推荐

  1. 【iOS Instrument性能优化集】

    iOS Instrument性能优化集 1.UIImage缓存取舍 在项目代码中看到大量使用如下代码: UIImage使用 在Main Thread中发现不同动画场景中Image IO 开销和耗时所占 ...

  2. Java基础加强之集合篇(模块记忆、精要分析)

    千里之行,始于足下.把别人的变成自己,再把自己的分享给别人,这也是一次提升的过程.本文的目的是以一篇文章从整体把握集合体系又不失一些细节上的实现,高手路过. 集合的作用与特点 Java是一门面向对象语 ...

  3. div高度根据内容自动增大

    1.很多时候我们希望容器高度能够自适应内部元素的变化,需要用到min-height属性. 2.有时候用了min-height还是不会随着内容自适应高度,您需要检查下容器的子元素是不是有浮动属性,当子元 ...

  4. XVI Open Cup named after E.V. Pankratiev. GP of Ukraine

    A. Associated Vertices 首先求出SCC然后缩点,第一次求出每个点能到的点集,第二次收集这些点集即可,用bitset加速,时间复杂度$O(\frac{nm}{64})$. #inc ...

  5. Lua 排行榜更新

    排行榜: key:玩家名字,val:玩家的数值 local key1 = {"a1", "a2", "b1", "b2" ...

  6. React-native之持久化保存----AsyncStorage

    AsyncStorage AsyncStorage是一个简单的,未加密的,异步的,持久化,关键值存储系统,是全局的. iOS中存储类似于NSUserDefault,存储问plist文件存放在设备中. ...

  7. PNG-8和PNG-24的抉择

    今天我做了一个图,因为需要透明,所以我存为了PNG8格式,结果发现图片变了,图片变得四周都不光滑了,四周都变得有锯齿了,而且阴影也不见了,后来存为PNG24,这些问题就消失了.我去百度搜索了关于PNG ...

  8. 第三周作业(三):wc程序

    本程序实现了统计文本档案中,文本单词数.字符数以及行数. 代码如下: #include<stdio.h> #include<stdlib.h> int linestatisti ...

  9. sequelize常见操作使用方法

    关于sequelize的准备工作这里不再赘述. 一.引入sequelize模块 var Sequelize = require('sequelize'); 二.连接数据库 var sequelize  ...

  10. Web前端面试之HTML

    1. 对WEB标准以及W3C的理解与认识 web标准规范要求,书写标签闭合.小写.不乱嵌套,可提高搜索机器人对网页内容的搜索几率.--- SEO 使用外链css和js脚本,结构与行为.结构与表现分离, ...