一,简介
jdk中提供了volatile关键字,用于修饰变量。提供了两层语义:
语义一:保证共享变量内存的可见性(并不能保证操作的原子性)。
语义二:禁用指令的重排序。
二,内存可见性原理分析
在Java内存模型中,内存分为主内存(堆内存)和工作内存(栈内存)两个部分,其中主内存是所有线程所共享的,而工作内存则是每个线程分配一份,各线程的工作内存彼此间独立、互不可见,在线程启动的时候,虚拟机为 每个线程分配一块工作内存,不仅包含了线程内部定义的局部变量,还包含了线程所需要使用的共享变量(非线程内构造的对象)的副本,即为了提高执行效率,读取副本比直接读取主内存更快,栈是连续的小空间、顺序入栈出栈,而堆是不连续的大空间,所以在栈中寻址的速度比堆要快很多)。各工作内存之间数据的交换通过主内存来进行的,如下图:
共享变量在工作内存中发生变化了之后,必须要写回到主内存中(迟早要写回但并非马上写回),但对于volatile关键字修饰的变量则要求工作内存中发生变化之后,必须马上写回到主内存,而线程每次要使用volatile修饰的共享变量时,都会直接到主内存中获取最新的值(而不是读取工作内存中的副本)。从而实现所有线程对该共享变量变化的可见性。
但volatile仅能保证变量的可见性,并不能保证操作的原子性:
假如线程A在做了i+1,但未赋值的时候,线程B就开始读取i,那么当线程A赋值i=1,并立即回写到主内存,而此时线程B已经不再需要i的值了,而是直接交给处理器去做+1的操作,于是当线程B执行完并回写到主内存,i的值仍然是1,而不是预期的2。
三,禁用指令重排序
synchronized、Lock以及volatile修饰符都可以禁用指令的重排序。
单例模式中双重检测机制:
private static volatile StoreKeeper instance = null; private StoreKeeper(){//对象初始化 } public static StoreKeeper getInstance(){ if(null == instance){ synchronized (StoreKeeper.class) { if(null == instance){ instance = new StoreKeeper(); } } } return instance; }
问题原因:
当a线程进入getinstance()方法,判断instance是null,然后执行instance = new StoreKeeper();但是实例化一个对象内部是很复杂的,有好多动作:
1.给这个对象分配空间
2.执行构造函数给成员赋值
3.将这个对象空间地址赋给instance变量
而根据java内存模型,在单个线程中,只要重排序不会对结果产生影响,那么就不能保证其中的操作一定按照程序写定的顺序执行---即使重排序对于其他线程来说会产生明显的影响,java存储模型允许编译器重排序操作,在寄存器中缓存数值,还允许cpu重排序,并在处理器特有的缓存中缓存数值,那么就是说线程a去实例化这个对象的时候可能是按照1-2-3的顺序执行,也可能是1-3-2的顺序执行
可能原因:如果是按照1-3-2执行顺序,那么当a线程执行完3这步的时候,cpu调度,这个时候b线程进来,判断instance是否为null,而此时instance肯定不为null,所以b线程就直接返回了这个对象
但是此时这个对象的所有成员变量还没有初始化成指定的值呢,因为线程a还没有来得及给成员变量赋值
构造方法还没有执行完,当b线程调用这个对象进行操作会产生无法预计的后果。
所以修改的方法是增加volatile关键字:private static volatile StoreKeeper instance;
相关推荐
java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java ...
C语言中关键字volatile的作用,使用说明和例子
Java并发编程:volatile关键字解析
一个定义为volatile 的变量是说这变量可能会被意想不到地改变,这样,编 译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必 须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里...
在本文里我们给大家分享的是关于java volatile关键字作用及使用场景的相关知识点内容,需要的朋友们学习下。
volatile关键字基本介绍 volatile可以看成是synchronized的一种轻量级的实现,但volatile并不能完全代替synchronized,volatile有synchronized可见性的特性,但没有synchronized原子性的特性。 可见性即用volatile...
C/C++ 嵌入式 一些关键字: volatile关键字 Const关键字 static关键字 mutable 关键字
volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情。这篇文章主要介绍了Java中volatile关键字的作用与用法详解的相关资料,需要的朋友可以参考下
一个生动的例子,详解了Volatile关键字对变量的声明在不同编译环境下可能造成不同的结果
java volatile 关键字 学习
主要讲述java线程volatile关键字
java里的volatile关键字详解
深入理解 volatile 关键字.doc
volatile是java中的关键词之一,这篇文章主要给大家介绍了关于Java中volatile关键字的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
6vc中volatile关键字的应用共4页.pdf.zip
详细描述关于votatile关键字使用,可以帮助你加深对volatile关键字的理解和使用。
java里的volatile关键字详解.pdf
C++Volatile关键字[参考].pdf
多方面解读Java中的volatile关键字.rar
java语言的volatile教程,java语言的volatile关键字到底怎么用