猿问

与Java中的易失性字段和同步块之间发生过关系-以及它们对非易失性变量的影响?

我对线程的概念还很陌生,并尝试进一步了解它。最近,我遇到了Jeremy Manson撰写的关于Java中的Volatile Means的博客文章,他在文章中写道:


当一个线程写一个易失性变量,而另一个线程看到该写操作时,第一个线程向第二个线程告知内存的所有内容,直到它执行对该易失性变量的写操作为止。[...] 所有的由线程1看到的存储内容,才写信给[volatile] ready,必须是可见的主题2,它读取值后true进行ready。[我自己加重]


现在,这是否意味着在写入volatile变量时线程1的内存中保存的所有变量(无论是否为volatile)在读取该volatile变量后对线程2都是可见的?如果是这样,是否有可能从Java官方文档/ Oracle来源中一起混淆该声明?从哪个Java版本开始可以使用?


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


private String s = "running";

private volatile boolean b = false;

线程1首先执行以下命令:


s = "done";

b = true;

然后线程2随后执行(在线程1写入volatile字段之后):


boolean flag = b; //read from volatile

System.out.println(s);

是否可以保证打印“完成”?


如果b在volatile我将写入和读取放入一个synchronized块时没有声明,该怎么办?


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


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


为什么?(抱歉;我无法在其他问题上发表评论,否则我会在那儿问...)


忽然笑
浏览 333回答 3
3回答

临摹微笑

是的,可以保证线程2将打印“ done”。当然,也就是说,如果b线程1中的写入实际上发生b在线程2中的读取之前,而不是同时发生或更早!推理的核心是事前发生的关系。多线程程序执行被视为由事件组成。事件可以通过事前发生关系来关联,即一个事件先于另一个事件发生。即使两个事件没有直接关联,如果您可以跟踪从一个事件到另一个事件的一系列先发生后关系,那么您可以说一个事件先于另一个事件发生。就您而言,您有以下事件:线程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

缥缈止盈

是否可以保证打印“完成”?如Java并发实践中所述:当线程A写入到一个volatile变量,然后线程B读取相同的变量,那名至A之前写可见的所有变量的值volatile读取后变量变得可见到B volatile变量。所以是的,这保证打印“完成”。如果不是将b声明为volatile而是将写入和读取放入同步块,会发生什么情况?这也将保证相同。不要使用volatile来保护多个共享状态。为什么?因为,volatile仅保证可见性。它不能保证原子性。如果我们在一个线程正在访问的方法中有两个易失性写操作,A而另一个线程B正在访问这些易失性变量,则在线程A执行该方法时,线程有可能在操作中间A被线程抢占B(例如在第一次volatile写入之后但在第二次volatile写入之前A)因此,保证操作的原子性synchronization是最可行的出路。
随时随地看视频慕课网APP

相关分类

Java
我要回答