Voliate关键字
Voliate关键字
禁止线程缓存变量结果。 可见性问题主要指一个线程修改了共享变量值,而另一个线程却看不到。 引起可见性问题的主要原因是每个线程拥有自己的一个高速缓存区——线程工作内存
1.Voliate保证可见性
- 不使用volatile关键字
public class Test {
private static Boolean stop = false;
public static void main(String[] args) throws InterruptedException {
// Thread-A
new Thread("Thread A") {
@Override
public void run() {
while (!stop) {
}
System.out.println(Thread.currentThread() + " stopped");
}
}.start();
Thread.sleep(100);
// Thread-B
new Thread("Thread B") {
@Override
public void run() {
stop = true;
System.out.println("started");
}
}.start();
}
}
一个线程内使用了停止的开关,假如这个stop没有被volatile修饰,我们在线程b中修改,线程a并不知道开关的值被修改了
---------------------------------------------------------------|-
console |
---------------------------------------------------------------|-
started |
|
---------------------------------------------------------------|-
2.Voliate保证有序性
- 使用volatile 防重排序
从一个最经典的例子来分析重排序问题。大家应该都很熟悉单例模式的实现
public class Singleton {
public static volatile Singleton singleton;
/**
* 构造函数私有,禁止外部实例化
*/
private Singleton() {};
public static Singleton getInstance() {
if (singleton == null) {
synchronized (singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}实例化一个对象其实可以分为三个步骤:
分配内存空间
初始化对象
将内存空间的地址赋值给对应的引用
但是由于操作系统可以对指令进行重排序,所以上面的过程也可能会变成如下过程:
分配内存空间
将内存空间的地址赋值给对应的引用
初始化对象
如果是这个流程,多线程环境下就可能将一个未初始化的对象引用暴露出来,从而导致不可预料的结果。
因此,为了防止这个过程的重排序,我们需要将变量设置为volatile类型的变量
- 使用volatile 保证原子性:单次读/写
- 对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量
- 但是并不能保证i++这种操作的原子性,因为本质上i++是读、写两次操作,要保证多步的原子性
- 可以通过AtomicInteger或者Synchronized来实现,本质上就是cas操作
3. 问题
3.1.i++为什么不能保证原子性?
i++其实是一个复合操作,包括三步骤:
读取i的值
对i加1
将i的值写回内存
volatile是无法保证这三个操作是具有原子性的
我们可以通过AtomicInteger或者Synchronized来保证+1操作的原子性
3.2.共享的long和double变量的为什么要用volatile?
- 因为long和double两种数据类型的操作可分为高32位和低32位两部分,
- 因此普通的long或double类型读/写可能不是原子的。
- 因此,鼓励大家将共享的long和double变量设置为volatile类型,
- 这样能保证任何情况下对long和double的单次读/写操作都具有原子性
4.总结
- 在某些操作下,voliate确实是可以保证原子性的。但设计之处,voliate并不是用于保证原子性
- 在复合操作下,例如i++,A线程执行完在i+1的操作但是还没写到内存的时候,即使使用了voliate保证了i的可见性,但是B线程此时看到的数据还是旧数据,那么就有可能出现数据错误
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类