为什么此Java程序包含两个易失性写入数据争用程序?

时间:2019-03-18 14:12:42

标签: volatile java-memory-model happens-before data-race

考虑以下Java程序:

Label

因为static volatile int shared; public static void main(final String[] args) { final Runnable r = () -> { shared = 1; }; new Thread(r).start(); new Thread(r).start(); } 被标记为shared,所以我想说这个程序没有数据争用。但是,如何基于JLS(例如版本11)来激发这种动机?

在第17章中,我们被告知:

  

当程序包含两个冲突访问(第17.4.1节)时,它们之间没有按事前发生关系进行排序,则该程序被称为包含数据争用。

我认为这是JLS提供的数据竞争的定义。然后我们有17.4.1节告诉我们:

  

如果至少有一次访问是写操作,则对同一变量的两次访问(读或写)被认为是冲突的。

好的,所以我们在这里有冲突的访问,因为我们有两次写入volatile的操作。现在,我们必须在两次写入之间具有先发生后发生的关系,否则我们将面临一场竞赛。但是,我还没有找到为什么我们在这里有这种关系。第17章告诉我:

  

如果动作x与后面的动作y同步,那么我们还有hb(x,y)。

同一章告诉我:

  

对易失性变量v(第8.3.1.4节)的写操作与任何线程对v的所有后续读取进行同步(其中“后续”根据同步顺序定义)。

但是在将写入与易失性变量相关联之前,我还没有发现任何事情发生。为什么会这样?

1 个答案:

答案 0 :(得分:1)

volatile 变量的访问不会从不受到数据竞争的约束。

在JLS中不是很明显,但是在短语中

  

(第17.4.1节)如果至少有一次访问是写操作,则对同一变量的两次访问(读或写)被认为是冲突的。

术语“读”和“写”不是通用的,但在下一部分“ 17.4.2操作”中将其描述为对非易失性变量的访问:

  

读取(正常或非易失性)。读取变量。

     

写入(正常或非易失性)。写一个变量。

在该部分中,对 volatile 变量的访问被归类为同步操作的一部分,并用不同的术语“易读”和“易写”:

  

易读。易读变量。

     

易失性写。可变地写变量。

因为只有(非易失性)读取和写入可能会发生冲突,所以只有那些访问可能包含数据竞争易失性的读取和写入不会发生冲突,并且绝不会包含数据争用