Java并行易失性I++

我有一个全局变量

volatile i = 0;

和两个线程。每个组件执行以下操作:

i++;
System.out.print(i);

我收到以下组合。12、21和22。

我理解为什么我不能得到11(易失性不允许缓存I)和我也理解12和22。

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

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

编辑:在运行代码10,000次之后,我得到了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是因为PrintStream未同步(请参阅Karol Dowbecki的答案)


解决方案

不幸的是++不是原子操作。尽管volatile不允许缓存,但允许JVM作为单独的操作进行读取、递增和写入。因此,你试图实现的概念是行不通的。您需要使用synchronized作为其互斥锁,或者使用类似于AtomicInteger的命令来提供原子增量操作。

相关文章