Java:使用两个线程计数

时间:2015-09-06 16:20:26

标签: multithreading concurrency

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

class Test
{
    int sum=0;

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

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

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

2 个答案:

答案 0 :(得分:2)

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

  1. 阅读变量
  2. 递增
  3. 将新值写回变量
  4. 由于(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