由于许多误解,我从头开始重新阐述了这个问题。问题的意图没有改变。许多评论仍然提到旧的问题文本。
有关volatile
的文档说明它确保其他线程以一致的方式查看内存更新。但是,很少使用volatile
。
据我所知,synchronized
块的目的是使线程不能同时执行这些关键部分。 synchronized
是否也会导致其他线程的内存更新一致,例如volatile
呢?
答案 0 :(得分:4)
当在锁定的部分内发生时,所有内存在Java中的线程之间是否一致地更新?
简答:
是。
答案很长:
在JVM中,引用类型的赋值和除double
和long
之外的所有基本类型都是" atomic"。即任何线程要么看到一个值,要么看到另一个值,但从不更新一半。所以你甚至可以说记忆是"始终如一"在没有做任何事情的情况下进行了更新(围绕这一点有一些微妙之处,所以不要尝试实际使用这个特性!它曾经被用来实现String#hashCode
)。
但是,如果没有volatile
,更改可能无法立即显示,就像您说的那样("立即"有点误导。有关详细信息,请参阅this answer)。 synchronized
关键字确实以与volatile
相同的方式立即显示更改。那么你问volatile
的重点是什么。
基本上,您可以使用volatile
执行synchronized
可以执行的任何操作。因此,volatile
并不能为您提供新功能。但是,它仍然有用,因为它避免了锁定。使用volatile
时,效果通常会更好(权衡功能较少; synchronized
可以执行volatile
可以执行的所有操作,但反之亦然)并且也没有死锁危险。 IMO如果您可以使用volatile
,则应使用volatile
。但是有很多人不同意并且认为你应该在任何地方使用synchronized
。
答案 1 :(得分:1)
Java并没有真正具有"易失性内存的概念"。相反,volatile
关键字会更改JVM对何时以及如何写入和读取字段所做的保证。维基百科对{(3}}的Java(和其他语言)的含义进行了很好的分解。
非常粗略地说,volatile
字段相当于一个总是读取和写入的字段,如下所示:
// read
T local;
synchronized {
local = field;
}
// ... do something with local
// write
synchronized {
field = local;
}
换句话说,volatile
字段的读取和写入是原子的,并且始终对其他线程可见。对于简单的并发操作,这已足够,但您仍可能需要显式同步以确保正确处理复合操作。 volatile
的优点是它更小(仅影响一个字段),因此可以比同步代码块更有效地处理。
你从我的伪翻译中注意到,对该字段的任何修改或变异都不是synchronized
,这意味着没有内存障碍或发生 - 在你可能对你做的任何事情上强加关系之前检索对象。 仅事物volatile
提供的是线程安全的字段读取和写入。这是一项功能,因为只需更新字段,它就比synchronized
块效率更高。
如果您以前没有,我强烈建议您阅读volatile
;它提供了有关Java中并发性所需知识的完美概述,包括volatile
和synchronized
之间的区别。
显然,这并没有发生,否则我在职业生涯中会遇到这样的问题。我从来没有。
请注意,这是一种错误的推理。你完全有可能做错事但从不受它的影响,或者根本不注意它的影响。例如,过度同步的代码(如Vector
)将正常工作,但运行速度比其他解决方案慢得多。
答案 2 :(得分:0)
当然,使用关键部分可行。使用volatile作品。但是你必须使用一些东西来确保你获得所需的内存可见性。否则,您的代码仅适用于运气或意外 - 如果有效。