在java中同步,确保其他线程的内存更新?

时间:2015-11-05 00:43:31

标签: java multithreading volatile

由于许多误解,我从头开始重新阐述了这个问题。问题的意图没有改变。许多评论仍然提到旧的问题文本。

有关volatile的文档说明它确保其他线程以一致的方式查看内存更新。但是,很少使用volatile

据我所知,synchronized块的目的是使线程不能同时执行这些关键部分。 synchronized是否也会导致其他线程的内存更新一致,例如volatile呢?

3 个答案:

答案 0 :(得分:4)

  

当在锁定的部分内发生时,所有内存在Java中的线程之间是否一致地更新?

简答:
是。

答案很长

在JVM中,引用类型的赋值和除doublelong之外的所有基本类型都是" 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中并发性所需知识的完美概述,包括volatilesynchronized之间的区别。

  

显然,这并没有发生,否则我在职业生涯中会遇到这样的问题。我从来没有。

请注意,这是一种错误的推理。你完全有可能做错事但从不受它的影响,或者根本不注意它的影响。例如,过度同步的代码(如Vector)将正常工作,但运行速度比其他解决方案慢得多。

答案 2 :(得分:0)

当然,使用关键部分可行。使用volatile作品。但是你必须使用一些东西来确保你获得所需的内存可见性。否则,您的代码仅适用于运气或意外 - 如果有效。