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

假设一个线程修改了一个共享变量的值,如果你没有对该变量使用volatile修饰符的话。当其他线程想要读取这个变量的值时,它们看不到更新后的值,因为它们是从CPU的缓存而不是RAM内存中读取变量的值。这个问题也被称为能见度问题。

通过将共享变量声明为volatile,所有对计数器变量的写入都将立即写入主存。同样,所有对counter变量的读取都将直接从主存中读取。

public class SharedObject {
    public volatile int sharedVariable = 0;
}

对于非易失性变量,不能保证Java虚拟机(JVM)何时将数据从主存读取到CPU缓存,或何时将数据从CPU缓存写入主存。这可能会导致几个问题,我将在下面的部分中解释这些问题。


例子:

想象这样一种情况,两个或多个线程可以访问一个共享对象,该对象包含一个声明如下的计数器变量:

public class SharedObject {
    public int counter = 0;
}

再想象一下,只有线程1增加计数器变量,但是线程1和线程2都可以不时地读取计数器变量。

如果计数器变量没有被声明为volatile,则不能保证计数器变量的值何时从CPU缓存写入主存。这意味着CPU缓存中的计数器变量值可能与主存中的不相同。这种情况如下所示:

线程看不到一个变量的最新值,因为它还没有被另一个线程写回主存,这个问题被称为“可见性”问题。一个线程的更新对其他线程是不可见的。

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

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

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

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

另一方面,

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

交谈,

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

如果您有一个多线程系统,这些多线程处理一些共享数据,这些线程将在它们自己的缓存中加载数据。如果我们不锁定资源,在一个线程中所做的任何更改都不会在另一个线程中可用。

使用锁定机制,我们可以添加对数据源的读/写访问。如果一个线程修改了数据源,该数据将存储在主存中而不是它的缓存中。当其他线程需要这个数据时,它们将从主存中读取它。这将显著增加延迟。

为了减少延迟,我们将变量声明为volatile。这意味着无论何时变量的值在任何处理器中被修改,其他线程都将被迫读取它。它仍然有一些延迟,但比从主存中读取要好。