Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么不';默认情况下,Java中的t变量是volatile吗?_Java_Multithreading_Volatile - Fatal编程技术网

为什么不';默认情况下,Java中的t变量是volatile吗?

为什么不';默认情况下,Java中的t变量是volatile吗?,java,multithreading,volatile,Java,Multithreading,Volatile,可能类似的问题: 今天我在调试我的游戏;它有一个非常困难的线程问题,每隔几分钟就会出现一次,但很难重现。因此,首先我将synchronized关键字添加到我的每个方法中。那没用。然后我将volatile关键字添加到每个字段。问题似乎自行解决了 经过一些实验,我发现负责的字段是一个GameState对象,它跟踪我的游戏的当前状态,可以是正在玩的,也可以是忙碌的。忙时,游戏会忽略用户输入。我所拥有的是一个线程,它不断地更改状态变量,而事件线程读取状态变量。但是,在一个线程更改变量后,另一个线程需

可能类似的问题:




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

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

通过使状态变量
可变
来修复该问题


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

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


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

长话短说,易变变量(无论是Java还是C)永远不会在线程中本地缓存。除非您处理的是多处理器/多核CPU,线程在不同的内核上执行,否则这并没有太大的意义,因为它们会查看相同的缓存。当您将一个变量声明为volatile时,所有读写操作都直接从实际的主内存位置开始,并直接到达主内存位置;没有涉及缓存。当涉及到优化时,这会产生影响,并且不必要地这样做(当大多数变量不需要波动时)会造成性能损失(可能微不足道,也可能微不足道)。声明变量波动通常会对性能产生巨大影响。在传统的单线程系统上,相对容易知道什么是易失性的;正是这些东西访问了硬件


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

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


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

只有当您试图编写低级别的线程安全、无锁代码时,才真正需要挥发物。您的大多数代码可能既不是线程安全的,也不是无锁的。根据我的经验,只有在您发现执行锁定的较简单版本由于锁定而导致性能显著下降之后,才值得尝试使用无锁编程

更令人愉快的选择是在
java.util.concurrent
中使用其他构建块,其中一些构建块是无锁的,但不会像尝试自己在较低的级别上完成这一切那样让你头脑混乱


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

我个人认为字段在默认情况下应该是最终的,并且只能通过一个额外的关键字进行修改,但这条船很久以前就已经开过了。

即使使用单核处理器,编译器(包括JIT编译器)也可能会决定优化对变量的访问。@Chris:我来自.NET背景,因此Java可能不同,但我不认为可以优化实例变量,除非它检测到从未使用过,局部变量不能声明为易变的(其实不需要),对吗?@Adam:它不能完全优化它。但是,类似“y=x*x”的内容可能只进入内存获取x的值一次,而不是两次。这是一个微不足道的例子。。。现在假设x在某个循环中展开并检查了几次。如果编译器从未看到您更改x的值,它可能会决定读取一次并在本地保留它。出于同样的原因,默认情况下不会同步方法。@mP:我不这么认为。Volatile和synchronized并不等同:Volatile不会导致死锁。我很好奇,我对Volatile变量的唯一体验是专门针对多线程访问的。在单线程环境中,易变变量背后的原因是什么?@Adam:在Java和C#中,我不太确定,尽管我认为JNI可能会让你玩一些游戏。在C/C++环境中,volatile对于指示该内存可能会从运行程序之外的其他地方(即映射到该内存位置的硬件)进行更改至关重要。由于Java和C#通常不会在硬件附近运行,这可能是一个不同的游戏。@AdamRobinson:即使在单线程环境中,Java也保留对独立命令重新排序的权利。例如:
x=1;y=2可改为
y=2;x=1。但是
x=z++;y=z++不应更改为
y=z++;x=z++。JVM不应该重新排序具有