JAVA中volatile关键字,在许多场合是不推荐使用的。因为,它容易使用不当导致不必要的问题。但是,如果使用得当,它能提供比锁更优的性能。
volatile单词的英文翻译为:易变的。它在JAVA中的语义就是来标明该变量是容易变化的,
提醒每次当线程读取该变量的时候都要从主内存中同步该变量的值。
在JAVA中有人把volatile看做是“程度较轻的 synchronized
”。与synchronized相比,volatile所需要的读写开销要小很多,但是它实现的功能也只有synchronized的一部分。锁提供了两种特性:互斥与可见性。互斥即为线程间的互斥访问,一次只允许一个线程持有某个特定的锁;可见性是指在线程对数据的修改,对后面访问的线程是可见的。Volatile 变量具有 synchronized
的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。
正确使用 volatile 变量的条件
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
- 对变量的写操作不依赖于当前值。
- 该变量没有包含在具有其他变量的不变式中。
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++
)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x
的值在操作期间保持不变,而 volatile 变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)
正确使用 volatile 的模式
很多并发性专家事实上往往引导用户远离 volatile 变量,因为使用它们要比使用锁更加容易出错。然而,如果谨慎地遵循一些良好定义的模式,就能够在很多场合内安全地使用 volatile 变量。要始终牢记使用 volatile 的限制 —— 只有在状态真正独立于程序内其他内容时才能使用 volatile —— 这条规则能够避免将这些模式扩展到不安全的用例。
模式 #1:状态标志
也许实现 volatile 变量的规范使用仅仅是使用一个布尔状态标志,用于指示发生了一个重要的一次性事件,例如完成初始化或请求停机。
很多应用程序包含了一种控制结构,形式为 “在还没有准备好停止程序时再执行一些工作”,
volatile boolean shutdownRequested;
...
public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
很可能会从循环外部调用
shutdown()
方法 —— 即在另一个线程中 —— 因此,需要执行某种同步来确保正确实现
shutdownRequested
变量的可见性。(可能会从 JMX 侦听程序、GUI 事件线程中的操作侦听程序、通过 RMI 、通过一个 Web 服务等调用)。然而,使用
synchronized
块编写循环要比使用清单 2 所示的 volatile 状态标志编写麻烦很多。由于 volatile 简化了编码,并且状态标志并不依赖于程序内任何其他状态,因此此处非常适合使用 volatile。
这种类型的状态标记的一个公共特性是:通常只有一种状态转换;shutdownRequested
标志从 false
转换为 true
,然后程序停止。这种模式可以扩展到来回转换的状态标志,但是只有在转换周期不被察觉的情况下才能扩展(从 false
到 true
,再转换到false
)。此外,还需要某些原子状态转换机制,例如原子变量。
分享到:
相关推荐
### STM32中Volatile变量的正确使用 #### 概述 在嵌入式系统编程中,`volatile`关键字的正确使用对于确保程序的稳定性和可靠性至关重要。它主要用于标记那些可能在程序运行过程中被外部因素(如硬件中断、多线程...
3. **volatile变量的错误使用示例**: ``` int square(volatile int *ptr) { return *ptr * *ptr; } ``` 这个函数有问题,因为它没有考虑到volatile变量的特性。在多线程环境下,*ptr的值可能在两次读取之间...
3. **使用volatile变量的潜在问题**:在使用`volatile`变量时,需要注意避免潜在的问题。例如,考虑以下函数: ```c int square(volatile int *ptr) { return *ptr * *ptr; } ``` 这段代码的目的是返回指针`...
### Java入门教程:数据类型与正确使用Volatile变量 #### 概述 在Java编程语言中,`volatile`关键字提供了一种轻量级的同步机制,用于确保共享变量的可见性和一定程度上的线程安全性。相比于传统的锁机制如`...
正确使用 volatile 变量的条件是:对变量的写操作不依赖于当前值,以及该变量没有包含在具有其他变量的不变式中。在实际应用中,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量...
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。 由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此...
本资料《深入探讨Java多线程中的volatile变量》将带你深入理解这个概念,全面解析其工作原理和实际应用。 volatile关键字在Java中主要用于解决多线程环境下的可见性和有序性问题。它确保了被volatile修饰的变量对...
本文将深入探讨`volatile`变量的概念、作用以及如何在实际编程中使用。 `volatile`变量的主要概念是它表明该变量的值可能在编译器无法预测的情况下发生变化。这种变化可能是由操作系统、硬件中断、多线程环境中的...
1. **单一状态标志**:如果一个变量仅仅用于标记状态,如线程是否需要停止,可以使用`volatile`。例如,`volatile boolean stop`,线程在检查`stop`变量时,能确保看到最新设置的值,从而决定是否停止运行。 2. **...
在Java编程语言中,`volatile`关键字是一个非常重要的并发控制机制,它被用来修饰类的成员变量,确保这些变量在多线程环境下的可见性和有序性。然而,使用`volatile`并非总是如我们所期望的那样简单,有时会出现一些...
volatile 关键字的使用方法可以分为两种情况:一是用来指定变量的存储类别,二是用来避免编译器的优化。 在第一个例子中,我们可以看到,使用 volatile 关键字可以避免编译器的优化。在这个例子中,我们定义了一个 ...
双重检查锁定模式是一种常见的volatile 变量使用场景。它可以用于避免在单例模式中创建对象时的同步开销。 模式 #3:事件触发器 volatile 变量也可以用于事件触发器,例如,在一个 GUI 应用程序中,使用 volatile ...
4. **谨慎使用**:虽然`volatile`提供了一种简单的方法来处理多线程环境中的共享变量,但它并不能解决所有的同步问题。在复杂的并发场景下,使用`volatile`可能不足以保证线程安全,需要结合其他的同步原语一起使用...
这是因为volatile变量的修改会直接写回主内存,其他线程在读取时会从主内存中获取最新值,而不是从各自的CPU缓存中读取,从而确保了数据的一致性。相比非volatile变量,线程可能会持有旧的副本,而无法感知到其他...
- 防止编译器优化:编译器通常会优化掉被认为不变的变量的读取,但volatile变量告诉编译器不要做这样的优化,每次使用时都从内存中读取。 - 多线程同步:在多线程环境中,当一个线程修改了volatile变量,其他线程...
使用volatile变量的例子1). 并行设备的硬件寄存器(如:状态寄存器)2). 一个中断服务子程序中会访问到的非自动变量(Non-automaticvari
SharedData结构包含了一个volatile的布尔型变量isProduced和isConsumed,以及一个整型变量data。 生产者线程负责生产数据并更新isProduced标志。 消费者线程等待isProduced标志为true,然后消费数据并更新isConsumed...
在使用volatile变量时,有三个关键的使用条件: 1. **写入操作不依赖于当前值**:如果一个线程更新volatile变量的值,并不依赖于变量当前的值,那么可以使用volatile。例如,设置一个标志位来标记某个任务是否完成...