Java:使用两个线程计数

问题描述 投票:0回答:2

假设线程A和B在以下Java代码中运行next函数:

class Test
{
    int sum=0;

    void next()
    {
        for(int i=0;i<100;i++)
            sum++;
    }
}

当两个线程完成下一个运行时,sum的价值可能是多少?我的答案是100-200。但是,我错过了一些案例。

是否存在sum的值小于100的情况?

multithreading concurrency
2个回答
2
投票

正如其他人之前所说的那样(包括你自己隐含),++增量运算符(前缀和后缀)都是非原子的,因此你的代码不是线程安全的。 Java Language Specification描述了在执行“Postfix Increment Operator ++”时幕后发生的事情。最相关的部分是它包含3个步骤:

  1. 读变量
  2. 递增
  3. 将新值写回变量

由于(1)和(3)对于ints来说是原子的,因此不存在任何按位损坏。步骤(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之间。


0
投票

我的答案是最小1和最大100。

增量代码如下: 1-mov ax,mem [sum] 2斧头 3-mov mem [sum],ax

现在让我们用for运行一个例子(int i = 0; i <3; i ++)

T1 line 1 | ==> ax = 0; MEM [总和] = 0; T1第2行| ==> ax = 1; MEM [总和] = 0; T2行1 | ==> ax = 0; MEM [总和] = 0; T1 line 3 | ==> ax = 0; MEM [总和] = 0; T2行2 | ==> ax = 1; MEM [总和] = 0; T1 line 1 | ==> ax = 0; MEM [总和] = 0; T2行3 | ==> ax = 0; MEM [总和] = 0; T1第2行| ==> ax = 1; MEM [总和] = 0; T2行1 | ==> ax = 0; MEM [总和] = 0; T1 line 3 | ==> ax = 0; MEM [总和] = 0; T2行2 | ==> ax = 1; MEM [总和] = 0; T1 line 1 | ==> ax = 0; MEM [总和] = 0; T2行3 | ==> ax = 0; MEM [总和] = 0; T1第2行| ==> ax = 1; MEM [总和] = 0; T2行1 | ==> ax = 0; MEM [总和] = 0; T1 line 3 | ==> ax = 0; MEM [总和] = 0; T2行2 | ==> ax = 1; MEM [总和] = 0; T2行3 | ==> ax = 1; MEM [总和] = 1;

这适用于i = 100

© www.soinside.com 2019 - 2024. All rights reserved.