挥发性关键字是一个神秘的关键字,也许在J2EE上的JAVA程序员会了解多一点,但在Android上的JAVA程序员大多不了解这个关键字。只要稍了解不当就好容易导致一些并发上的错误发生,例如好多人把挥发性理解成变量的锁。(并不是)
<>强挥发性的特性:强>
具备可见性
保证不同线程对被挥发性修饰的变量的可见性。
有一被挥发性修饰的变量我,在一个线程中修改了此变量,对于其他线程来说我的修改是立即可见的。
如:
不稳定的int i=0;//语句1 我+ +;//语句2
语句2执行完后,我最新的值会立即被强制更新到主内存(共享内存),并通知其他缓存了我的线程,令其他线程的工作内存里的我失效,从而需重新到主内存读取最新的值。
具备有序性
被挥发性修饰的变量,不会被优化排序。
解决的问题详见:Java多线程并发编程并发三大要素的三,有序性。
当编译器在给程序优化排序时,若遇到挥发性变量的读操作或者写操作,则会保证在其前面的操作全部进行完成,且结果对后面的操作可见,并且保证在其后面的操作没有进行。
不具备原子性
挥发性不具备原子性,所以它是线程不安全的。
实验:
//一个单例的实现 公开课SingletonTest { 私有静态稳定SingletonTest mInstance=零; 私人SingletonTest () {} 公共静态SingletonTest getInstance () { 如果(mInstance==null) { mInstance=new SingletonTest (); system . out。println(“初始化完成”); } 返回mInstance; } }//测试代码 公共类测试{ 公共静态void main (String [] var0) { for (int i=0;我& lt;20;我+ +){ ThreadTest测试=new ThreadTest (); test.start (); } } 静态类ThreadTest延伸线{ @Override 公共空间run () { super.run (); SingletonTest.getInstance (); } } }
结果:
每次运行都输出多个“初始化完成”。
<>强挥发性的解释强>
下面这段话摘自《深入理解Java虚拟机》:
"观察加入动荡的关键字和没有加入动荡的关键字时所生成的汇编代码发现,加入动荡的关键字时,会多出一个锁前缀指令”
被挥发性修饰的变量进行读和写操作的时候,在相应的汇编程序中都会多一句内存屏障(内存屏障)。
而这个锁就是内存屏障。
<强>内存屏障的作用:强>
1,在重新优化排序时保证其后面的指令不会被排到内存屏障的前面,前面的指令也不会排到内存屏障的后面。-有序性
2,强制对写操作后的结果(立即)刷新到主内存。
3,刷新结果到主内存时,通知并令其他线程缓存内的值过期/失效。
2和3合起来则是可见性。
说到这里,也许会有好多人困惑,既然可见性可以保证,既然可以做到修改某个变量的值后,会刷新到主内存,并令其他线程缓存失效,为什么不能保证原子性呢?这也是我之前走进的一个困区。
继续用我+ +来分析一下,这里面包含的指令:
从主内存读取到缓存//指令1
进行运算//指令2
从缓存刷新到主内存//指令3
内存屏障//指令4
虽然指令4(内存屏障)功能强大,但可惜//指令1、2、3都不是具备原子性,所以导致波动不具备原子性,线程不安全,不能替代锁的作用。
<强>使用场景强>
如一些简单的状态标记:
动荡的布尔请来=false;//线程1 init ();//语句1 请=true;//语句2//线程2 而(初始化){ 工作();//语句3 } >之前1,可确保语句1和语句2的执行顺序。
2,可确保执行语句2后,线程2可立即获取到最新的修改,从而执行语句3 .Java多线程并发编程动荡的关键字