JavaScript 中的变量读写安全及实现互斥锁
type
status
date
slug
summary
tags
category
icon
password
虽然 JavaScript 是单线程,但有时也不得不考虑变量读写的原子性问题。一旦对变量的读写被 await 打断,原子性被破坏,就可能遇到不符合常规同步编程思维的意外惊喜。为了保证获得预期的行为,我们可以想办法实现一个基于 Promise 的互斥锁
 
先看这样一段代码
运行结果显而易见:count: 100
但是,稍作修改
这时,我们发现输出神奇地变为了:count: 1
好吧,也不神奇,原因很简单,当我们加了一行 await Promise.resolve() 之后,这个 add 函数的代码就被一分为二了。await 之前的代码和 await 之后的代码不是连续执行的。
为了方便解释,我们将 add 函数中 await 之前的部分称为 P1,之后剩下的部分称为 P2。 当第一个 add 函数执行完 P1 时,P2 不会紧接着被执行,cpu 会立即去执行第二个 add 函数的 P1,依此类推,直至所有的 P1 都被执行完毕。这时我们就可以发现,由于所有的 P1 执行的时候,还没有任何一个 P2 执行,所以所有的 add 函数在 P1 中取到的 count 都是 0,那么赋给 temp 变量的值也都是 0。最后,当 P2 依次被执行的时候,又会将 temp + 1 的结果赋回给 count,所以最终 count 的输出就是 1
是不是和多线程中的变量读写情况有点类似。所以,虽然 JavaScript 是单线程,但有时也不得不考虑变量读写的原子性问题。一旦对变量的读写被 await 打断,原子性被破坏,就可能遇到不符合常规同步编程思维的意外惊喜。
至于解决方法,这里为了将表面同步实则异步贯彻到底,提供一个 "加锁" 的办法。利用 Promise 实现一个互斥锁,代码如下:
然后就能看到输出又变回了预期中的 count: 100

基于以上互斥锁实现读写锁
测试略过

© Ezekiel 2022-2025