`

Volatile的正确使用

    博客分类:
  • java
阅读更多
以前就看到过Volatile关键字, 只知道跟多线程同步有关, 但一直没去过问具体的含义。
今天想了起来, 查找了一下Volatile相关资料。
就理解而言,看这篇文章就足够了:
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

以下我还是做一下自问自答,以示学习和理解的过程。

一、什么是Volatile?
引用

Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。

这里说volatile 是轻量的同步,又跟同步方法和同步块放在一起,说是同步机制。其实在看过之后的内容后,我倒觉得即使volatile是同步机制的一种,但也不合适将volatile 跟synchronized立刻扯到一起来介绍,因为很容易让人以为volatile跟synchronized用的一样的锁方法实现的,但实际上它又不全是。

再看这个就会有个认识:
引用

锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。

volatile 实际上只保证了可见性跟synchronized相同,但又不会有互斥。Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。

看到这里, 你一定会疑问volatile什么时候用?怎样用?
引用

什么时候用到volatile?
如果读操作远远大于写操作,出于简易性或可伸缩性的考虑,您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时,某些习惯用法(idiom)更加易于编码和阅读。此外,volatile 变量不会像锁那样造成线程阻塞,因此也很少造成可伸缩性问题,volatile 变量还提供优于锁的性能优势。


引用

正确的使用volatile:
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
    * 对变量的写操作不依赖于当前值。
    * 该变量没有包含在具有其他变量的不变式中。
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。


下面可以看看使用volatile 的典型场景,可以帮助理解:
引用

volatile boolean shutdownRequested;

...

public void shutdown() { shutdownRequested = true; }

public void doWork() { 
    while (!shutdownRequested) { 
        // do stuff
    }
}

很可能会从循环外部调用 shutdown() 方法 —— 即在另一个线程中 —— 因此,需要执行某种同步来确保正确实现 shutdownRequested 变量的可见性。(可能会从 JMX 侦听程序、GUI 事件线程中的操作侦听程序、通过 RMI 、通过一个 Web 服务等调用)。然而,使用 synchronized 块编写循环要比以上所示的 volatile 状态标志编写麻烦很多。由于 volatile 简化了编码,并且状态标志并不依赖于程序内任何其他状态,因此此处非常适合使用 volatile。


看看volatile的性能:
引用

使用 volatile 变量的主要原因是其简易性:在某些情形下,使用 volatile 变量要比使用相应的锁简单得多。使用 volatile 变量次要原因是其性能:某些情况下,volatile 变量同步机制的性能要优于锁。

很难做出准确、全面的评价,例如 “X 总是比 Y 快”,尤其是对 JVM 内在的操作而言。(例如,某些情况下 VM 也许能够完全删除锁机制,这使得我们难以抽象地比较 volatile 和 synchronized 的开销。)就是说,在目前大多数的处理器架构上,volatile 读操作开销非常低 —— 几乎和非 volatile 读操作一样。而 volatile 写操作的开销要比非 volatile 写操作多很多,因为要保证可见性需要实现内存界定(Memory Fence),即便如此,volatile 的总开销仍然要比锁获取低。

volatile 操作不会像锁一样造成阻塞,因此,在能够安全使用 volatile 的情况下,volatile 可以提供一些优于锁的可伸缩特性。如果读操作的次数要远远超过写操作,与锁相比,volatile 变量通常能够减少同步的性能开销。


再看看一个相对开销较低的读-写锁策略
引用

@ThreadSafe
public class CheesyCounter {
    // Employs the cheap read-write lock trick
    // All mutative operations MUST be done with the 'this' lock held
    @GuardedBy("this") private volatile int value;

    public int getValue() { return value; }

    public synchronized int increment() {
        return value++;
    }
}

之所以将这种技术称之为 “开销较低的读-写锁” 是因为您使用了不同的同步机制进行读写操作。因为本例中的写操作违反了使用 volatile 的第一个条件,因此不能使用 volatile 安全地实现计数器 —— 您必须使用锁。然而,您可以在读操作中使用 volatile 确保当前值的可见性,因此可以使用锁进行所有变化的操作,使用 volatile 进行只读操作。其中,锁一次只允许一个线程访问值,volatile 允许多个线程执行读操作,因此当使用 volatile 保证读代码路径时,要比使用锁执行全部代码路径获得更高的共享度 —— 就像读-写操作一样。然而,要随时牢记这种模式的弱点:如果超越了该模式的最基本应用,结合这两个竞争的同步机制将变得非常困难。



总结:
与锁相比,Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。
Volatile相比synchronized,并没有保证原子性操作,因此不能用在需要加锁的环境,但可以跟synchronized结合,实现开销较低的读写锁。
使用Volatile,需要严格遵循 volatile 的使用条件:
1)即变量真正独立于其他变量和自己以前的值
2)该变量没有包含在具有其他变量的不变式中
因此volatile 事实上的应用场景常常应该是变量和边界检查,但又要注意以上两个规则。
某些情况下,需要保证原子性操作,还是得用到lock。
需要记住,使用 volatile 的代码往往比使用synchronized的代码更加容易出错,不能单为了更好的性能、却忽略了本来应该保证的安全性。
最好结合这篇讨论一起看:
http://www.iteye.com/topic/109150?page=1
分享到:
评论

相关推荐

    stm32 volatile变量的正确使用

    ### STM32中Volatile变量的正确使用 #### 概述 在嵌入式系统编程中,`volatile`关键字的正确使用对于确保程序的稳定性和可靠性至关重要。它主要用于标记那些可能在程序运行过程中被外部因素(如硬件中断、多线程...

    volatile的使用方法

    在第三个例子中,我们可以看到,使用 volatile 关键字可以避免编译器的优化,并且可以确保变量的值是正确的。在这个例子中,我们定义了一个 volatile 的变量 bdata var,然后使用它来控制数组 values 的值。由于我们...

    Volatile的正确使用1

    这里我们深入探讨一下`volatile`的正确使用和限制。 首先,`volatile`变量确保了线程间的可见性,即一旦一个线程修改了`volatile`变量的值,其他线程能立即看到这个更新。这得益于Java内存模型(JMM)的规定,`...

    const,extern,static,volatile的使用

    ### const、extern、static、volatile 的使用详解 #### 一、const 的使用 **1. 为什么使用 const** `const` 关键字在 C 和 C++ 编程语言中非常常见,它...正确地使用这些关键字可以极大地提高代码的质量和可维护性。

    volatile使用详解

    - 示例:如果多个任务需要通过共享变量来协调它们的行为,那么这些变量应该使用 `volatile` 来标记,以确保线程间能够正确地同步状态。 3. **硬件寄存器访问**:存储器映射的硬件寄存器通常也需要用 `volatile` ...

    Volatile详解,深入学习Volatile

    《深入理解Volatile》 ...正确理解和使用volatile可以避免不必要的数据冲突,提高程序的正确性和可靠性。但在使用时,需要注意其局限性,特别是在多线程环境下,volatile并不能完全替代同步机制。

    volatile的使用1

    【volatile关键字】在Java编程语言中扮演着至关重要的角色,主要负责解决并发环境下的数据同步问题。volatile确保了变量在多线程环境下的...理解并正确使用volatile,可以帮助开发者编写出更高效、更安全的多线程代码。

    AVR-GCC 中如何使用volatile 关键字.pdf

    - 在涉及硬件控制和中断处理的场景中,正确使用 `volatile` 关键字至关重要。 - 对于那些不确定是否需要使用 `volatile` 的变量,可以通过分析变量的使用场景来决定是否有必要使用。 总之,`volatile` 关键字在AVR-...

    volatile用法

    `volatile`关键字在C语言中是一个非常重要的概念,主要用于处理多线程环境或者与硬件交互时的内存可见性问题。它的主要作用是确保对变量的修改能够立即...理解和正确使用`volatile`对于编写健壮的并发代码至关重要。

    Java线程:volatile关键字

    正确使用 volatile 变量的条件是:对变量的写操作不依赖于当前值,以及该变量没有包含在具有其他变量的不变式中。在实际应用中,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量...

    java入门教程:数据类型_Java理论与实践如何正确使用Volatile变量.docx

    ### Java入门教程:数据类型与正确使用Volatile变量 #### 概述 在Java编程语言中,`volatile`关键字提供了一种轻量级的同步机制,用于确保共享变量的可见性和一定程度上的线程安全性。相比于传统的锁机制如`...

    volatile的用法

    Volatile是C语言中的一个类型修饰符,用于告诉编译器该变量可能会在程序的控制之外被改变,从而...通过以上知识点,我们可以了解到volatile在保证程序正确性方面的关键作用,以及如何在实际编程中正确使用volatile。

    volatile详解

    如果这些变量在中断发生时被修改,那么使用`volatile`可以确保这些变量的值被正确更新。 3. **多线程应用中的共享变量**:在多线程环境中,多个线程可能会共享同一个变量。如果某个线程修改了这个变量的值,那么...

    volatile源码分析1

    在深入理解volatile时,我们需要考虑JVM内存模型、处理器缓存以及底层的汇编指令,这有助于我们更好地理解和使用volatile,解决并发编程中的问题。在实际开发中,合理利用volatile可以避免不必要的锁同步,提升程序...

    Java 关键字 volatile 的理解与正确使用

    Java 关键字 volatile 的理解与正确使用 Java 语言中关键字 volatile 被称作轻量级的 synchronized,与 synchronized 相比,volatile 编码相对简单且运行时的开销较少,但能够正确合理地应用好 volatile 并不是那么...

    单片机C语言中volatile的作用

    ### 单片机C语言中volatile的作用 在探讨单片机C语言中`volatile`关键字的作用之前,我们首先需要理解`volatile`的基本...正确地理解和使用`volatile`不仅可以帮助开发者避免潜在的错误,还能提高程序的可靠性和性能。

    详解java如何正确使用volatile

    Java中的`volatile`关键字在多线程编程中扮演着至关重要的角色,它的主要功能是确保在并发环境中,被volatile修饰的变量对所有线程都具有实时可见性,...理解和正确使用`volatile`关键字对于优化并发代码性能至关重要。

    volatile 变量的说明

    volatile变量在编程语言中,尤其是Java和C/C++中,是一种特殊的标识符,用于指示编译器该变量的值可能在编译器不知情的情况下发生变化。...理解和正确使用volatile是编写高效、可靠的并发程序的关键。

    C中volatile_const解析

    理解和正确使用`volatile`和`const`关键字对于编写高质量的C语言代码至关重要,尤其是在嵌入式系统开发中。通过确保编译器正确处理这些变量,可以避免许多难以调试的错误,提高系统的稳定性和可靠性。

Global site tag (gtag.js) - Google Analytics