为什么Java中的变量不是默认的volatile?

时间:2009-06-13 03:16:39

标签: java multithreading volatile

可能类似的问题:

Do you ever use the volatile keyword in Java?

<小时/> 今天我正在调试我的游戏;它有一个非常困难的线程问题,每隔几分钟就出现一次,但很难重现。首先,我在每个方法中添加了synchronized关键字。那没用。然后我将volatile关键字添加到每个字段。问题似乎只是解决了问题。

经过一些实验,我发现负责的字段是一个GameState对象,它跟踪我的游戏当前状态,可以是正在播放也可以是忙碌。忙时,游戏会忽略用户输入。我所拥有的是一个不断更改state变量的线程,而Event线程读取state变量。但是,在一个线程更改变量后,另一个线程需要几秒钟来识别更改,这最终会导致问题。

通过制作状态变量volatile来修复它。

默认情况下,为什么Java volatile中没有变量,以及不使用volatile关键字的原因是什么?

6 个答案:

答案 0 :(得分:32)

总而言之,易变量 - 无论是Java还是C# - 都不会在线程中本地缓存。除非您正在处理在不同内核上执行线程的多处理器/多核CPU,否则这并没有多大意义,因为它们正在查看相同的缓存。当您将变量声明为volatile时,所有读取和写入都直接来自并直接进入实际的主存储器位置;没有涉及缓存。当涉及到优化时,这会产生影响,并且不必要地(当大多数变量不需要变化时)这样做会对性能造成损失(尽管可能会或可能不会很小),但收益相对较小。

答案 1 :(得分:10)

当您尝试编写低级线程安全的无锁代码时,实际上只需要Volatiles。您的大多数代码可能不应该 线程安全无锁。根据我的经验,只有在您发现执行锁定的更简单版本由于锁定而导致性能大幅下降后才能尝试无锁编程。

更令人愉快的选择是使用java.util.concurrent中的其他构建块,其中一些是无锁的,但不要像在低级别尝试自己做的那么多。

Volatility有自己的性能成本,并且大多数代码都没有理由承担这些成本。

答案 2 :(得分:8)

就我个人而言,我认为字段应该是默认的最终字段,并且只有一个额外的关键字才可变,但是那条船在很久以前就已经航行了。 ;)

答案 3 :(得分:6)

虽然其他人指出为什么默认为volatile是个坏主意是正确的,但还有另外一点要做:代码中很可能存在错误。 变量很少需要使用volatile:总是有一种方法可以正确地同步对变量的访问(通过synchronized关键字,或者使用来自java.util.concurrency的AtomicXxx对象):异常包括操作这些的JNI代码(不受同步约束)指令)。

因此,您可能想要找出解决问题的原因,而不是添加volatile。它不是解决问题的唯一方法,而且可能有更好的方法。

答案 4 :(得分:5)

因为编译器无法优化volatile变量。

volatile告诉编译器变量可以随时更改。因此,它不能假设变量不会相应地改变和优化。

答案 5 :(得分:2)

声明变量volatile通常会对性能产生巨大影响。在传统的单线程系统中,相对容易知道需要变化的东西;是那些访问硬件的东西。

在多线程上,它可能会稍微复杂一点,但我通常会鼓励使用通知和事件队列来处理魔术变量中的theads之间的数据传递。在Java中它可能并不重要;在C / C ++中,当这些变量无法由底层硬件原子设置时,你会遇到麻烦。