假设线程A和B在以下Java代码中运行next
函数:
class Test
{
int sum=0;
void next()
{
for(int i=0;i<100;i++)
sum++;
}
}
当两个线程完成下一个运行时,sum
的值是什么?
我的答案是100-200。但是,我错过了一些案例。
是否存在sum的值小于100的情况?
答案 0 :(得分:2)
正如其他人之前所说的那样(包括你自己隐含),++
增量运算符(前缀和后缀)都是非原子的,因此你的代码不是线程安全的。 Java Language Specification描述了在执行&#34; Postfix Increment Operator ++
&#34;期间幕后发生的事情。最相关的部分是它包含3个步骤:
由于(1)和(3)是int
s的原子,因此不存在任何按位损坏。步骤(2)本身也可以完美地运行,因为它仅适用于线程本地数据。
因此,我们留下的唯一可能问题是经典的Lost Update Problem。
由于丢失的更新只会降低结果,我同意你的上限为200.如果代码是在增量操作实际 原子操作的平台上运行的(Java语言规范不禁止这种情况),或者如果所有线程在完全增量完成后,或者如果一个线程没有被调度直到另一个线程完成,则巧合地切换。
现在我的下限甚至比你低。您对100的猜测可能是基于以下想法:为了丢失一个更新,我们需要另一个更新来覆盖它。因此,我们永远不会失去一半以上的增量。但这实际上是错误的,因为一个线程的单个增量可以消灭另一个线程的几个增量,请参阅此示例交错:
Thread A || Thread B
=====================================================
read sum (0) ||
|| read sum(0)
|| increment sum locally(1)
|| write sum(1)
|| read sum(1)
|| increment sum locally(2)
|| write sum(2)
|| read sum(2)
|| increment sum locally(3)
|| write sum(3)
increment sum locally(1) ||
write sum(1) ||
但是,为了消灭一个线程的增量,我们需要在另一个线程中至少有一个成功的增量。由于必须消除两个线程的增量才能获得最低结果(否则我们将至少有100个成功增量),我们需要在两个线程中至少有一次成功更新,因此总共需要2次成功增加。
这个最小值可以达到,例如使用以下交错:
Thread A || Thread B
========================================================
read sum (0) ||
|| read sum (0)
|| increment sum locally (1)
|| write sum (1)
|| read sum (1)
|| increment sum locally (2)
|| write sum (2)
|| read sum (2)
|| increment sum locally (3)
|| write sum (3)
||
|| ... 95 more increments ...
||
|| read sum (98)
|| increment sum locally (99)
|| write sum (99)
increment sum locally(1) ||
write sum (1) ||
|| read sum (1)
read sum (1) ||
increment sum locally(2) ||
write sum (2) ||
read sum (2) ||
increment sum locally(3) ||
write sum (3) ||
read sum (3) ||
increment sum locally(4) ||
write sum (4) ||
||
... 95 more increments ... ||
||
read sum (99) ||
increment sum locally(100) ||
write sum (100) ||
|| increment sum locally (2)
|| write sum (2)
所以答案是: 2个主题的值可以在2到200之间。
答案 1 :(得分:0)
我的回答是最低1和最高100。
增量代码如下:
1-mov ax,mem [sum]
2-inc ax
3-mov mem [sum],ax
现在让我们用for(int i = 0; i&lt; 3; i ++)
运行一个例子 T1第1行| ==&gt; ax = 0; MEM [总和] = 0;
T1第2行| ==&gt; ax = 1; MEM [总和] = 0;
T2行1 | ==&gt; ax = 0; MEM [总和] = 0;
T1第3行| ==&gt; ax = 0; MEM [总和] = 0;
T2行2 | ==&gt; ax = 1; MEM [总和] = 0;
T1第1行| ==&gt; ax = 0; MEM [总和] = 0;
T2第3行| ==&gt; ax = 0; MEM [总和] = 0;
T1第2行| ==&gt; ax = 1; MEM [总和] = 0;
T2行1 | ==&gt; ax = 0; MEM [总和] = 0;
T1第3行| ==&gt; ax = 0; MEM [总和] = 0;
T2行2 | ==&gt; ax = 1; MEM [总和] = 0;
T1第1行| ==&gt; ax = 0; MEM [总和] = 0;
T2第3行| ==&gt; ax = 0; MEM [总和] = 0;
T1第2行| ==&gt; ax = 1; MEM [总和] = 0;
T2行1 | ==&gt; ax = 0; MEM [总和] = 0;
T1第3行| ==&gt; ax = 0; MEM [总和] = 0;
T2行2 | ==&gt; ax = 1; MEM [总和] = 0;
T2第3行| ==&gt; ax = 1; MEM [总和] = 1;
同样适用于i = 100