发生在与Java中的易失性字段和同步块之间的关系之前 – 及其对非易失性variables的影响?

我对线程的概念还是比较陌生的,试着更多地了解它。 最近,我遇到了一篇关于杰里米·曼森(Jarremy Manson)的“ 什么是挥发性手段(What Volatile Means in Java)”的博文,他写道:

当一个线程写入一个volatilevariables,另一个线程看到写入时,第一个线程告诉第二个线程关于所有内存的内容,直到写入该volatilevariables。 在线程1写入[volatile] ready之前,线程1看到的所有内存内容必须对线程2可见,然后它读取ready的值true 。 [强调自己加]

现在,这是否意味着在写入volatilevariables时线程1的内存中保存的所有variables(volatile或不)在线程2读取该volatilevariables之后将变为可见? 如果是这样, 是否有可能从官方的Java文档/ Oracle来源拼凑这个声明? 从哪个Java版本开始这个工作?

特别是,如果所有线程共享以下类variables:

 private String s = "running"; private volatile boolean b = false; 

线程1首先执行以下操作:

 s = "done"; b = true; 

线程2然后执行(线程1写入易失性字段后):

 boolean flag = b; //read from volatile System.out.println(s); 

这将保证打印“完成”?

如果不是将b声明为volatile而是将写入和读取放入synchronized块,会发生什么?

此外,在题为“ 线程之间共享静态variables? ”的讨论中,@TREE 写道 :

不要使用volatile来保护多个共享状态。

为什么? (对不起;我还不能评论其他问题,或者我会问那里…)

是的,这是保证线程2将打印“完成”。 当然,如果在线程2中写入b实际上发生在线程2中的b之前,而不是在同一时间或更早发生!

这里的推理的核心是发生之前的关系 。 multithreading程序执行被视为由事件组成。 事件可以通过发生在关系之前相关联,即一个事件发生在另一个事件之前。 即使两个事件不是直接相关的,如果你可以追踪一连串的事件 – 在从一个事件到另一个事件之间的关系之前,那么你可以说一个事件发生在另一个事件之前。

在你的情况下,你有以下事件:

  • 线程1写入s
  • 线程1写入b
  • 线程2从b读取
  • 线程2从s读取

以下规则起作用:

  • “如果x和y是同一个线程的动作,并且x按照程序顺序在y之前,那么hb(x,y)”。 ( 节目顺序规则)
  • “写一个易失性字段(第8.3.1.4节)发生在每个后续读取该字段之前”。 ( 易变规则)

发生以下情况 – 因此存在关系:

  • 线程1写入s发生线程1写入b (程序顺序规则)
  • 线程1写入b发生在线程2从b读取 (易失规则)
  • 线程2从b读取发生在线程2从s读取 (程序顺序规则)

如果你遵循这个链条,你可以看到,结果是:

  • 线程1写入s发生在线程2从s读取之前

如果不是将b声明为volatile,而是将写入和读取放入同步块,会发生什么?

当且仅当你使用相同的锁保护所有这样的同步块时,才能保证与你的volatile例子一样的可见volatile 。 此外,您还将相互排除这种同步块的执行。

不要使用volatile来保护多个共享状态。

为什么?

volatile不能保证primefaces性:在你的例子中, svariables也可能在你正在显示的write之后被其他线程改变; 阅读线程将无法保证所看到的值。 同样的事情发生在读取volatile ,但在读取s之前发生。

在实践中做什么是安全的, 共享不变的状态 ,通过写入一个volatilevariables的引用可以传递。 所以也许这就是“一个共同的国家”的意思。

是否有可能从官方的Java文档/ Oracle源拼图这个声明?

行情从规格:

17.4.4。 同步顺序

对volatilevariablesv(§8.3.1.4)的写入与任何线程(其中“后续”根据同步顺序定义)的所有后续v读取进行同步。

17.4.5。 在订单之前发生

如果x和y是同一个线程的动作,并且x按照程序顺序在y之前,那么hb(x,y)。

如果动作x与下一个动作y同步,那么我们也有hb(x,y)。

这应该够了。

从哪个Java版本开始这个工作?

Java语言规范第三版引入了重写内存模型规范,这是上述保证的关键。 NB大多数以前的版本充当保证在那里,许多代码行实际上依赖于它。 当人们发现保证其实不在那里时,人们感到惊讶。

这将保证打印“完成”?

正如Java实践中的并发 :

当线程A写入一个volatilevariables,然后线程B读取同一个variables时, 写入volatilevariables之前A对A可见的所有variables的值在读取volatilevariables后对B变得可见

所以是的 ,这保证打印“完成”。

如果不是将b声明为volatile,而是将写入和读取放入同步块,会发生什么?

这也将保证一样。

不要使用volatile来保护多个共享状态。

为什么?

因为,挥发性只保证可见性。 它不能保证primefaces性。 如果在线程A正在访问的方法中有两个易失性写入,而另一个线程B正在访问这些易失性variables,那么当线程A正在执行该方法时,线程A可能会被线程B抢占(例如,在第一次易失性写入之后,但在线程A第二次易失性写入之前)。 所以保证操作synchronization的primefaces性是最可行的出路。