Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java并行易失性i++;_Java_Multithreading_Increment_Runnable_Race Condition - Fatal编程技术网

Java并行易失性i++;

Java并行易失性i++;,java,multithreading,increment,runnable,race-condition,Java,Multithreading,Increment,Runnable,Race Condition,我有一个全局变量 volatile i = 0; 和两条线。每种方法都有以下作用: i++; System.out.print(i); 我收到以下组合。12、21和22 我理解为什么我没有得到11(volatile不允许缓存I),我也理解12和22 我不明白的是怎么可能得到21分 获得这种组合的唯一可能方法是,以后打印的线程必须首先将i从0增加到1,然后缓存i==1。然后另一个线程将i从1增加到2,然后打印2。然后第一个线程打印缓存的i==1。但是我认为,volatile不允许缓存 编辑:在

我有一个全局变量

volatile i = 0;
和两条线。每种方法都有以下作用:

i++;
System.out.print(i);
我收到以下组合。12、21和22

我理解为什么我没有得到11(volatile不允许缓存I),我也理解12和22

我不明白的是怎么可能得到21分

获得这种组合的唯一可能方法是,以后打印的线程必须首先将
i
从0增加到1,然后缓存
i==1
。然后另一个线程将
i
从1增加到2,然后打印2。然后第一个线程打印缓存的
i==1
。但是我认为,
volatile
不允许缓存

编辑:在运行代码10000次后,我得到了11次。将
volatile
添加到
i
不会改变可能的组合

markspace是正确的:volatile禁止缓存
i
,但
i++
不是原子的。这意味着在增量期间,
i
仍然在寄存器中获得某种“缓存”

r1 = i
//if i changes here r1 does not change
r1 = r1 + 1 
i = r1

这就是为什么11仍然是可能的。21是因为PrintStreams没有同步(请参见Karol Dowbecki的回答)

您的代码不能保证哪个线程将首先调用


由于
volatile
关键字,
i
的增量和读取按顺序发生,但prints没有。不幸的是
++
不是原子操作。尽管
volatile
不允许缓存,但允许JVM作为单独的操作进行读取、递增和写入。因此,您试图实现的概念是行不通的。您需要为其互斥体使用
synchronized
,或者使用类似于
AtomicInteger
的东西,它确实提供了原子增量操作

唯一可能的方法是,稍后打印的线程必须首先将i从0增加到1,然后缓存i==1

你忘记了什么是
System.out.print(i)
does:该语句调用
System.out
对象的
print(…)
方法,调用时使用
i
中存储的任何值

所以这里有一个可能发生的情况:

Thread A
increments i  (i now equals 1)
Starts to call `print(1)`  //Notice! that's the digit 1, not the letter i.
gets bogged down somewhere deep in the guts...

          Thread B
          increments i (i=2)
          Calls `print(2)`
          Gets lucky, and the call runs to completion.

Thread A
finishes its `print(1)` call.

两个线程都没有缓存
i
变量。但是,
System.out.print(…)
函数对您的
volatile inti
一无所知。它只知道传递给它的值(1或2)。

正如我在下面回答的那样,“volatile不允许缓存”并不是严格正确的说法。因为读、增量和写都是可能并行发生的独立操作,
i
的值可以有效地被缓存。@markspace我想说,只要以前发生过,就允许。这可以在缓存一致性级别完成。良好的编辑。另一个争论点是,您没有解决volatile++固有的竞争条件。请参阅@markspace的答案。你可能会得到123445。。。