你到底什么时候在 Java 中使用 volatile 关键字? [英] When exactly do you use the volatile keyword in Java?

查看:41
本文介绍了你到底什么时候在 Java 中使用 volatile 关键字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已阅读何时在 Java 中使用 'volatile'?"但我我还是很困惑.我怎么知道什么时候应该将变量标记为 volatile?如果我弄错了,要么在需要它的东西上省略 volatile,要么将 volatile 放在不需要它的东西上怎么办?在确定多线程代码中哪些变量应该是 volatile 时,有哪些经验法则?

I have read "When to use 'volatile' in Java?" but I'm still confused. How do I know when I should mark a variable volatile? What if I get it wrong, either omitting a volatile on something that needs it or putting volatile on something that doesn't? What are the rules of thumb when figuring out what variables should be volatile in multithreaded code?

推荐答案

当你想让一个成员变量被多个线程访问但不需要复合原子性时,你基本上会使用它(不确定这是否是正确的术语).

You basically use it when you want to let a member variable be accessed by multiple threads but do not need compound atomicity (not sure if this is the right terminology).

class BadExample {
    private volatile int counter;

    public void hit(){
        /* This operation is in fact two operations:
         * 1) int tmp = this.counter;
         * 2) this.counter = tmp + 1;
         * and is thus broken (counter becomes fewer
         * than the accurate amount).
         */
        counter++;
    }
}

上面是一个不好的例子,因为你需要复合原子性.

the above is a bad example, because you need compound atomicity.

 class BadExampleFixed {
    private int counter;

    public synchronized void hit(){
        /*
         * Only one thread performs action (1), (2) at a time
         * "atomically", in the sense that other threads can not 
         * observe the intermediate state between (1) and (2).
         * Therefore, the counter will be accurate.
         */
        counter++;
    }
}

现在来看一个有效的例子:

Now to a valid example:

 class GoodExample {
    private static volatile int temperature;

    //Called by some other thread than main
    public static void todaysTemperature(int temp){
        // This operation is a single operation, so you 
        // do not need compound atomicity
        temperature = temp;
    }

    public static void main(String[] args) throws Exception{
        while(true){
           Thread.sleep(2000);
           System.out.println("Today's temperature is "+temperature);
        }
    }
}

现在,你为什么不能只使用private static int temperature?事实上,您可以(从某种意义上说,您的程序不会炸毁或其他东西),但是另一个线程对 temperature 的更改可能对主线程可见",也可能不可见".

Now, why can't you just use private static int temperature? In fact you can (in the sense that that your program won't blow up or something), but the change to temperature by the other thread may or may not be "visible" to the main thread.

基本上这意味着您的应用程序甚至有可能.如果您使用volatile,则永远保持写入Today's temperature is 0(实际上,该值往往最终会变得可见.但是,您不应该冒险在必要时不使用 volatile,因为它会导致令人讨厌的错误(由不完全构造的对象等引起).

Basically this means that it is even possible that your app. keeps writing Today's temperature is 0 forever if you don't use volatile (in practice, the value tends to become eventually visible. However, you should not risk not using volatile when necessary, since it can lead to nasty bugs (caused by in-completely constructed objects etc.).

如果你把 volatile 关键字放在不需要 volatile 的东西上,它不会影响你的代码的正确性(即行为不会改变).在性能方面,它将取决于 JVM 实现.从理论上讲,您可能会因为编译器无法进行重新排序优化、必须使 CPU 缓存无效等而导致性能略有下降,但是编译器可以再次证明您的字段永远无法被多个线程访问并消除 volatile 关键字,并将其编译为相同的指令.

If you put volatile keyword on something that doesn't need volatile, it won't affect your code's correctness (i.e. the behaviour will not change). In terms of performance, it will depend on the JVM implementation. In theory you might get a tiny performance degradation because the compiler can't do reordering optimisations, have to invalidate CPU cache etc., but then again the compiler could prove that your field cannot ever be accessed by multiple threads and remove the effect of volatile keyword completely and compile it to identical instructions.


对此评论的回复:


Response to this comment:

好的,但是为什么我们不能使 todaysTemperature 同步并为温度创建一个同步的 getter?

Ok, but why can't we make todaysTemperature synchronized and create a synchronized getter for temperature?

您可以,并且它会正确运行.volatile 可以做的任何事情都可以用 synchronized 完成,但反之则不行.如果可以,您可能更喜欢 volatile 的原因有两个:

You can and it will behave correctly. Anything that you can with volatile can be done with synchronized, but not vice versa. There are two reasons you might prefer volatile if you can:

  1. 不易出错:这取决于上下文,但在许多情况下,使用 volatile 不太容易出现并发错误,例如在持有锁时阻塞、死锁等.
  2. 更高的性能:在大多数 JVM 实现中,volatile 可以显着提高吞吐量和更好的延迟.然而,在大多数应用中,差异很小,无关紧要.
  1. Less bug prone: This depends on the context, but in many cases using volatile is less prone to concurrency bugs, like blocking while holding the lock, deadlocks etc.
  2. More performant: In most JVM implementations, volatile can have significantly higher throughput and better latency. However in most applications the difference is too small to matter.

这篇关于你到底什么时候在 Java 中使用 volatile 关键字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆