Java volatile 关键字有什么用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/106591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:22:40  来源:igfitidea点击:

What is the volatile keyword useful for

javamultithreadingkeywordvolatile

提问by Richard

At work today, I came across the volatilekeyword in Java. Not being very familiar with it, I found this explanation:

今天在工作中,我遇到了volatileJava 中的关键字。对它不是很熟悉,我找到了这个解释:

Java theory and practice: Managing volatility

Java 理论与实践:管理波动性

Given the detail in which that article explains the keyword in question, do you ever use it or could you ever see a case in which you could use this keyword in the correct manner?

鉴于该文章对相关关键字的详细解释,您是否曾经使用过它,或者您是否见过可以以正确方式使用该关键字的案例?

采纳答案by Greg Mattes

volatilehas semantics for memory visibility. Basically, the value of a volatilefield becomes visible to all readers (other threads in particular) after a write operation completes on it. Without volatile, readers could see some non-updated value.

volatile具有内存可见性的语义。基本上,一个volatile字段的值在写入操作完成后对所有读者(特别是其他线程)可见。如果没有volatile,读者可能会看到一些未更新的值。

To answer your question: Yes, I use a volatilevariable to control whether some code continues a loop. The loop tests the volatilevalue and continues if it is true. The condition can be set to falseby calling a "stop" method. The loop sees falseand terminates when it tests the value after the stop method completes execution.

回答您的问题:是的,我使用一个volatile变量来控制某些代码是否继续循环。循环测试该volatile值,如果是 则继续true。可以false通过调用“停止”方法来设置条件。循环false在 stop 方法完成执行后测试该值时看到并终止。

The book "Java Concurrency in Practice," which I highly recommend, gives a good explanation of volatile. This book is written by the same person who wrote the IBM article that is referenced in the question (in fact, he cites his book at the bottom of that article). My use of volatileis what his article calls the "pattern 1 status flag."

我强烈推荐的《Java 并发实践》一书很好地解释了volatile. 这本书是由撰写问题中引用的 IBM 文章的同一个人撰写的(实际上,他在那篇文章的底部引用了他的书)。我使用的volatile是他的文章所说的“模式 1 状态标志”。

If you want to learn more about how volatileworks under the hood, read up on the Java memory model. If you want to go beyond that level, check out a good computer architecture book like Hennessy & Pattersonand read about cache coherence and cache consistency.

如果您想了解更多关于内部volatile工作原理的信息,请阅读Java 内存模型。如果您想超越该级别,请查看像Hennessy & Patterson这样的优秀计算机体系结构书籍并阅读有关缓存一致性和缓存一致性的内容。

回答by Ande Turner

“… the volatile modifier guarantees that any thread that reads a field will see the most recently written value.”- Josh Bloch

If you are thinking about using volatile, read up on the package java.util.concurrentwhich deals with atomic behaviour.

The Wikipedia post on a Singleton Patternshows volatile in use.

“...... volatile 修饰符保证任何读取字段的线程都会看到最近写入的值。” - Josh Bloch

如果您正在考虑使用volatile,请阅读java.util.concurrent处理原子行为的包。

维基百科上关于单例模式的帖子显示了使用中的 volatile。

回答by dgvid

Absolutely, yes. (And not just in Java, but also in C#.) There are times when you need to get or set a value that is guaranteed to be an atomic operation on your given platform, an int or boolean, for example, but do not require the overhead of thread locking. The volatile keyword allows you to ensure that when you read the value that you get the currentvalue and not a cached value that was just made obsolete by a write on another thread.

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

回答by Dave L.

One common example for using volatileis to use a volatile booleanvariable as a flag to terminate a thread. If you've started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag. To stop it, set the flag to true. By making the flag volatile, you can ensure that the thread that is checking it will see it has been set the next time it checks it without having to even use a synchronizedblock.

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

回答by ykaganovich

Yes, volatile must be used whenever you want a mutable variable to be accessed by multiple threads. It is not very common usecase because typically you need to perform more than a single atomic operation (e.g. check the variable state before modifying it), in which case you would use a synchronized block instead.

是的,只要您希望多个线程访问可变变量,就必须使用 volatile。这不是很常见的用例,因为通常您需要执行多个原子操作(例如,在修改之前检查变量状态),在这种情况下,您将使用同步块。

回答by Rudi Adianto

You'll need to use 'volatile' keyword, or 'synchronized' and any other concurrency control tools and techniques you might have at your disposal if you are developing a multithreaded application. Example of such application is desktop apps.

如果您正在开发多线程应用程序,您将需要使用 'volatile' 关键字或 'synchronized' 以及您可能拥有的任何其他并发控制工具和技术。此类应用程序的示例是桌面应用程序。

If you are developing an application that would be deployed to application server (Tomcat, JBoss AS, Glassfish, etc) you don't have to handle concurrency control yourself as it already addressed by the application server. In fact, if I remembered correctly the Java EE standard prohibit any concurrency control in servlets and EJBs, since it is part of the 'infrastructure' layer which you supposed to be freed from handling it. You only do concurrency control in such app if you're implementing singleton objects. This even already addressed if you knit your components using frameworkd like Spring.

如果您正在开发将部署到应用程序服务器(Tomcat、JBoss AS、Glassfish 等)的应用程序,您不必自己处理并发控制,因为它已由应用程序服务器处理。事实上,如果我没记错的话,Java EE 标准禁止在 servlet 和 EJB 中进行任何并发控制,因为它是“基础设施”层的一部分,您应该从处理它中解放出来。如果您要实现单例对象,则只能在此类应用程序中进行并发控制。如果您使用像 Spring 这样的框架来编织组件,这甚至已经解决了。

So, in most cases of Java development where the application is a web application and using IoC framework like Spring or EJB, you wouldn't need to use 'volatile'.

因此,在应用程序是 Web 应用程序并使用 Spring 或 EJB 等 IoC 框架的 Java 开发的大多数情况下,您不需要使用“易失性”。

回答by MB.

Yes, I use it quite a lot - it can be very useful for multi-threaded code. The article you pointed to is a good one. Though there are two important things to bear in mind:

是的,我经常使用它 - 它对于多线程代码非常有用。你指的那篇文章很好。虽然有两个重要的事情要记住:

  1. 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.
  2. 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.
  1. 如果您完全了解它的作用以及它与同步的区别,您应该只使用 volatile。在许多情况下,从表面上看, volatile 似乎是一个更简单、更高效的 synchronized 替代方案,而对 volatile 的更好理解通常会表明 synchronized 是唯一可行的选择。
  2. 尽管 synchronized 可以,但 volatile 实际上在很多旧的 JVM 中都不起作用。我记得看过一个文档,其中提到了不同 JVM 中不同级别的支持,但不幸的是我现在找不到了。如果您使用的是 Java 1.5 之前的版本,或者您无法控制程序将在其上运行的 JVM,请务必查看它。

回答by Pyrolistical

volatileis very useful to stop threads.

volatile对于停止线程非常有用。

Not that you should be writing your own threads, Java 1.6 has a lot of nice thread pools. But if you are sure you need a thread, you'll need to know how to stop it.

并不是说您应该编写自己的线程,Java 1.6 有很多不错的线程池。但是,如果您确定需要一个线程,则需要知道如何停止它。

The pattern I use for threads is:

我用于线程的模式是:

public class Foo extends Thread {

  private volatile boolean close = false;

  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

In the above code segment, the thread reading closein the while loop is different from the one that calls close(). Without volatile, the thread running the loop may never see the change to close.

在上面的代码段中,closewhile循环中的线程读取与调用的线程不同close()。如果没有 volatile,运行循环的线程可能永远不会看到要关闭的更改。

Notice how there's no need for synchronization

请注意如何不需要同步

回答by fatih tekin

volatileonly guarantees that all threads, even themselves, are incrementing. For example: a counter sees the same face of the variable at the same time. It is not used instead of synchronized or atomic or other stuff, it completely makes the reads synchronized. Please do not compare it with other java keywords. As the example shows below volatile variable operations are also atomic they fail or succeed at once.

volatile只保证所有线程,甚至它们自己,都在递增。例如:计数器同时看到变量的同一面。它不是用来代替同步或原子或其他东西,它完全使读取同步。请不要将其与其他 java 关键字进行比较。正如下面的示例所示,易失性变量操作也是原子的,它们会立即失败或成功。

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

Even you put volatile or not results will always differ. But if you use AtomicInteger as below results will be always same. This is same with synchronized also.

即使你把 volatile 或 not 结果总是不同的。但是,如果您使用 AtomicInteger 如下,结果将始终相同。这与同步也是一样的。

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

回答by Aniket Thakur

In my opinion, two important scenarios other than stopping thread in which volatile keyword is used are:

在我看来,除了停止使用 volatile 关键字的线程之外,两个重要的场景是:

  1. Double-checked locking mechanism. Used often in Singleton design pattern. In this the singleton object needs to be declared volatile.
  2. Spurious Wakeups. Thread may sometimes wake up from wait call even if no notify call has been issued. This behavior is called spurious wakeup. This can be countered by using a conditional variable (boolean flag). Put the wait() call in a while loop as long as the flag is true. So if thread wakes up from wait call due to any reasons other than Notify/NotifyAll then it encounters flag is still true and hence calls wait again. Prior to calling notify set this flag to true. In this case the boolean flag is declared as volatile.
  1. 双重检查锁定机制。常用于单例设计模式。在这种情况下,单例对象需要声明为 volatile
  2. 虚假唤醒。即使没有发出通知调用,线程有时也可能从等待调用中唤醒。这种行为称为虚假唤醒。这可以通过使用条件变量(布尔标志)来解决。只要标志为真,就将 wait() 调用置于 while 循环中。因此,如果线程由于 Notify/NotifyAll 以外的任何原因从等待调用中唤醒,则它遇到标志仍然为真,因此再次调用等待。在调用 notify 之前将此标志设置为 true。在这种情况下,布尔标志被声明为 volatile