什么时候在Java中使用volatile关键字?

什么时候在Java中使用volatile关键字?

我读过“ 什么时候在Java中使用'volatile'? ”但我仍然感到困惑。我怎么知道何时应该标记变量volatile?如果我弄错了,要么在需要它的东西上省略volatile,要么在不需要的东西上放置volatile呢?在确定多线程代码中哪些变量应该是易变的时,有哪些经验法则?



达令说
浏览 779回答 3
3回答

小怪兽爱吃肉

当你想让一个成员变量被多个线程访问但不需要复合原子性(不确定这是否是正确的术语)时,你基本上使用它。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++;     }}以上是一个不好的例子,因为你需要复合原子性。 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++;     }}现在来看一个有效的例子: 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另一个线程的改变可能对主线程“可见”,也可能不是“可见”。基本上这意味着你的应用甚至可能。Today's temperature is 0如果你不使用volatile,它会永远写作(在实践中,这个值最终会变得可见。但是,你不应该冒险在必要时不使用volatile,因为它可能会导致令人讨厌的错误(由完全构造的对象等引起)。 )。如果将volatile关键字放在不需要的东西上volatile,它不会影响代码的正确性(即行为不会改变)。在性能方面,它将取决于JVM实现。从理论上讲,由于编译器无法进行重新排序优化,不得不使CPU缓存等无效,因此可能会出现微小的性能下降,但再次编译器可以证明多个线程无法访问您的字段并删除volatile关键字的影响完全并将其编译为相同的指令。编辑:回复此评论:好的,但是为什么我们不能让todaysTemperature同步并为温度创建一个同步的getter?你可以,它会表现正常。您可以使用的任何东西volatile都可以完成synchronized,但反之亦然。volatile如果可以,您可能会有两个理由:减少错误:这取决于上下文,但在许多情况下使用volatile不太容易出现并发错误,例如在持有锁时阻塞,死锁等。性能volatile更高:在大多数JVM实现中,可以具有更高的吞吐量和更好的延迟。然而,在大多数应用中,差异太小而无关紧要。

绝地无双

易失性在无锁算法中最有用。当您不使用锁定来访问该变量并且您希望一个线程所做的更改在另一个线程中可见时,或者您希望创建“发生后”关系以确保计算是不再重新订购,以确保在适当的时间可见变化。该JMM食谱介绍了哪些操作可以被重新排序,哪些不能。

PIPIONE

volatile 关键字保证volatile变量的值总是从主内存中读取,而不是从Thread的本地缓存中读取。来自java并发教程:使用volatile变量可以降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取相同变量的先发生关系这意味着对volatile变量的更改始终对其他线程可见。它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用。关于你的查询:我怎么知道何时应该标记变量volatile?在确定多线程代码中哪些变量应该是易变的时,有哪些经验法则?如果您认为所有读者线程始终获得变量的最新值,则必须将变量标记为 volatile如果您有一个编写器线程来修改变量和多个读取器线程的值来读取变量的值,那么volatile修饰符可以保证内存的一致性。如果您有多个线程来写和读取变量,volatile单独使用修饰符并不能保证内存一致性。你必须synchronize在代码或使用高水平并发结构,如Locks,Concurrent Collections,Atomic variables等。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java