今天工作时,我在Java中遇到了volatile关键字。不是很熟悉,我找到了这个解释。

鉴于那篇文章详细解释了所讨论的关键字,您曾经使用过它吗?或者您曾经看到过以正确方式使用该关键字的情况吗?


当前回答

volatile关键字有两种不同的用法。

阻止JVM从寄存器(假设为缓存)读取值,并强制从内存读取其值。 降低内存不一致错误的风险。

阻止JVM读取寄存器中的值,并强制其读取 从内存中读取的值。

busy标志用于防止线程在设备繁忙且该标志不受锁保护的情况下继续运行:

while (busy) {
    /* do something else */
}

当另一个线程关闭busy标志时,测试线程将继续执行:

busy = 0;

但是,由于busy在测试线程中经常被访问,JVM可以通过将busy的值放在寄存器中来优化测试,然后在每次测试之前测试寄存器的内容,而不读取内存中的busy值。测试线程永远不会看到busy的变化,而另一个线程只会改变内存中的busy值,从而导致死锁。将busy标志声明为volatile将强制在每次测试之前读取它的值。

降低内存一致性错误的风险。

使用易失性变量可以降低内存一致性错误的风险,因为对易失性变量的任何写入都会建立一个 “happens-before”关系与该变量的后续读取之间的关系。这意味着对volatile变量的更改总是对其他线程可见。

这种读写而不产生记忆一致性错误的技术被称为原子动作。

原子作用是指有效地同时发生的作用。原子的动作不可能中途停止:它要么完全发生,要么根本不发生。在操作完成之前,原子操作的副作用是不可见的。

下面是你可以指定的原子操作:

对于引用变量和大多数变量来说,读和写都是原子的 基本变量(所有类型,除了long和double)。 对于所有声明为volatile的变量,读和写都是原子的 (包括长变量和双变量)。

干杯!

其他回答

The volatile key when used with a variable, will make sure that threads reading this variable will see the same value . Now if you have multiple threads reading and writing to a variable, making the variable volatile will not be enough and data will be corrupted . Image threads have read the same value but each one has done some chages (say incremented a counter) , when writing back to the memory, data integrity is violated . That is why it is necessary to make the varible synchronized (diffrent ways are possible)

如果修改是由一个线程完成的,而其他线程只需要读取这个值,则volatile将是合适的。

用volatile关键字声明的变量有两个主要特性,这使得它很特殊。

如果我们有一个易失性变量,它不能被任何线程缓存到计算机的(微处理器)缓存内存中。访问总是发生在主存中。 如果对一个易失性变量正在进行写操作,并且突然请求了一个读操作,那么可以保证写操作将在读操作之前完成。

以上两个品质推断了这一点

所有读取volatile变量的线程肯定会读取最新的值。因为没有缓存值可以污染它。而且读请求只有在当前写操作完成后才会被授予。

另一方面,

如果我们进一步研究我提到的#2,我们可以看到volatile关键字是维护一个共享变量的理想方法,它有n个读线程,只有一个写线程可以访问它。一旦我们添加了volatile关键字,就完成了。没有任何线程安全方面的开销。

交谈,

我们不能仅仅使用volatile关键字来满足有多个写入线程访问它的共享变量。

是的,当你想要一个可变变量被多个线程访问时,必须使用volatile。这不是很常见的用例,因为通常你需要执行不止一个原子操作(例如,在修改变量之前检查变量状态),在这种情况下,你会使用同步块代替。

对于长变量和双变量类型的读写操作的处理,目前还没有人提及。读和写对于引用变量和大多数基本变量都是原子操作,长变量和双变量类型除外,它们必须使用volatile关键字作为原子操作。@link

使用volatile的一个常见示例是使用volatile布尔变量作为终止线程的标志。如果您已经启动了一个线程,并且希望能够安全地从另一个线程中断它,您可以让线程定期检查标志。要阻止它,将标志设置为true。通过将标志设置为易失性,可以确保正在检查它的线程在下次检查时看到它已经设置好,甚至不必使用同步块。