13

可能类似的问题:

你曾经在 Java 中使用过 volatile 关键字吗?


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

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

它是通过使状态变量来修复的volatile

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

4

6 回答 6

35

长话短说,volatile 变量——无论是 Java 还是 C#——永远不会在线程中本地缓存。除非您正在处理具有在不同内核上执行的线程的多处理器/多核 CPU,否则这并没有太大的意义,因为它们会查看相同的缓存。当您将变量声明为 volatile 时,所有读取和写入都直接来自并直接到达实际的主内存位置;不涉及缓存。这在优化方面会产生影响,并且不必要地这样做(当大多数变量不需要是 volatile 时)将造成性能损失(可能是微不足道的,也可能不是微不足道的)以获得相对较小的收益。

于 2009-06-13T03:22:32.657 回答
10

只有当您尝试编写低级线程安全、无锁代码时,才真正需要 Volatile。您的大部分代码可能不应该线程安全的无锁的。以我的经验,无锁编程只有在您发现执行锁定的更简单版本由于锁定而导致性能显着下降之后才值得尝试

更令人愉快的选择是在 中使用其他构建块java.util.concurrent,其中一些是无锁的,但不会像尝试在低级别自己做所有事情那样搞砸你的脑袋。

波动性有其自身的性能成本,大多数代码没有理由产生这些成本。

于 2009-06-13T05:54:25.210 回答
8

就我个人而言,我认为默认情况下字段应该是最终的,并且只能通过额外的关键字进行可变,但是那艘船很久以前就已经航行了。;)

于 2009-06-13T08:14:17.620 回答
6

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

因此,您可能想弄清楚为什么它解决了问题,而不是添加 volatile。这不是解决它的唯一方法,可能还有更好的方法。

于 2009-06-13T04:18:39.403 回答
5

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

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

于 2009-06-13T03:21:13.473 回答
2

声明变量 volatile 通常会对性能产生巨大影响。在传统的单线程系统上,很容易知道什么是易变的;正是那些东西访问了硬件。

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

于 2009-06-13T03:47:59.680 回答