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

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


当前回答

下面是一个非常简单的代码,演示了volatile for variable的需求,它用于从其他线程控制线程执行(这是需要volatile的一个场景)。

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

当不使用volatile时:即使在“stop on: xxx”之后,你也永远不会看到“Stopped on: xxx”消息,并且程序继续运行。

Stopping on: 1895303906650500

当使用volatile时:你会立即看到'Stopped on: xxx'。

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

演示:https://repl.it/repls/SilverAgonizingObjectcode

其他回答

绝对是的。(不仅是Java, c#也是如此。)有时,您需要获取或设置一个值,该值保证是给定平台上的原子操作,例如int或boolean,但不需要线程锁定的开销。volatile关键字允许您确保在读取值时获得的是当前值,而不是在另一个线程上写入时被废弃的缓存值。

每个访问volatile字段的线程在继续之前都会读取它的当前值,而不是(可能)使用缓存的值。

只有成员变量可以是易变的或瞬变的。

是的,我经常使用它——它对多线程代码非常有用。你指的那篇文章很好。不过有两件重要的事情要记住:

You should only use volatile if you completely understand what it does and how it differs to synchronized. In many situations volatile appears, on the surface, to be a simpler more performant alternative to synchronized, when often a better understanding of volatile would make clear that synchronized is the only option that would work. volatile doesn't actually work in a lot of older JVMs, although synchronized does. I remember seeing a document that referenced the various levels of support in different JVMs but unfortunately I can't find it now. Definitely look into it if you're using Java pre 1.5 or if you don't have control over the JVMs that your program will be running on.

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

Volatile变量是轻量级同步。当所有线程之间的最新数据可见性是必需的,并且原子性可能会受到损害时,在这种情况下,Volatile变量必须是首选。对volatile变量的读取总是返回任何线程最近完成的写操作,因为它们既不缓存在寄存器中,也不缓存在其他处理器看不到的缓存中。Volatile是无锁的。当场景满足上面提到的条件时,我使用volatile。