Javascript线程处理和竞争条件

时间:2014-01-30 21:02:29

标签: javascript multithreading synchronization thread-safety race-condition

假设我有以下代码:

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如何处理其线程,何时在线程之间切换,是否有可用于处理竞争条件的内置方法?

2 个答案:

答案 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);

一旦两次超时都被解雇,shared150还是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()),则可能会遇到竞争条件。