假设我有以下代码:
var shared = 100;
function workWithIt(){
shared += 100;
}
setTimeout(workWithIt, 500);
setTimeout(workWithIt, 500);
理想情况下,这段代码应该为变量shared
添加200,之后为300。
但是,正如我从c
所知,如果将操作+ =拆分为多个命令,可能会有一些含义。
让我们说,这是函数的执行顺序:
setTimeout() --> create Thread A
setTimeout() --> create Thread B
wait 500ms
**Thread A** | **Thread B**
--------------------------------+---------------------------------
var tmpA = shared; //100 |
| var tmpB = shared; //100
| tmpB = tmpB+100; //tmpB=200
| shared = tmpB;
tmpA = tmpA+100; //tmpA=200 |
shared = tmpA; |
在这种情况下,shared
现在的值为200。
这可能发生在许多编程语言中,如c,c ++,java,c#,...... - 但是它也可以在Javascript中发生吗?
或者更一般地说:Javascript如何处理其线程,何时在线程之间切换,是否有可用于处理竞争条件的内置方法?
答案 0 :(得分:6)
JavaScript代码只有一个显式执行线程。您所描述的场景永远不会在JavaScript中发生。计时器回调只是另一种事件,所有事件都被序列化,以便由浏览器UI线程的同一核心事件循环顺序执行。
因此,两个计时器事件不能同时处理,一个回调将在另一个之后发生。
您仍然可以通过Web Workers在JavaScript中实现真正的并发。但是,Web worker不能与另一个Web worker或主线程共享任何对象。相反,Web工作者使用JSON序列化其状态对象,并使用postMessage
交换消息。所以,你的情景仍然是不可能的。
但是,请考虑另一种情况:
var shared = 100;
function workWithIt1(){
shared += 100;
}
function workWithIt2(){
shared = shared/2;
}
setTimeout(workWithIt1, 500);
setTimeout(workWithIt2, 500);
一旦两次超时都被解雇,shared
会150
还是100
?它可能是100
,因为workWithIt1
超时排在第一位。但是,我不会依赖这个事实,因为两个定时器都具有相同的超时值500
,并且定时器的实现可能是特定于浏览器的。您可能希望避免代码中的副作用。
答案 1 :(得分:1)
AFAIK,JS中没有多线程。我改变了你的例子以试图理解你的意思。
var shared = 100;
function workWithIt(a){
shared += a||100;
console.log(shared);
}
setTimeout(function(){workWithIt(5);}, 500);
setTimeout(function(){workWithIt(10);}, 500);
console.log(shared);
使用此代码,结果总是(在我的测试中):
100
105
110
这向我表明,这里没有混乱或随机甚至有趣的过程。在浏览器中使用JS创建赛车条件有一定的可能性,但您的计时示例不是这样。赛车只需要对执行顺序的可预测性进行细分。如果您将延迟时间从500
更改为Math.floor(500 * Math.random())
,则可能会遇到竞争条件。