(转)java之用volatile和不用volatile的区别

news/2024/7/7 16:07:03

在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。 



要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。 


Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 

 

用volatile和不用volatile的区别,运行一下,就知道了。

不用volatile:

 

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. package com.keyword;  
  2.   
  3. public class TestWithoutVolatile {  
  4.     private static boolean bChanged;  
  5.   
  6.     public static void main(String[] args) throws InterruptedException {  
  7.         new Thread() {  
  8.   
  9.             @Override  
  10.             public void run() {  
  11.                 for (;;) {  
  12.                     if (bChanged == !bChanged) {  
  13.                         System.out.println("!=");  
  14.                         System.exit(0);  
  15.                     }  
  16.                 }  
  17.             }  
  18.         }.start();  
  19.         Thread.sleep(1);  
  20.         new Thread() {  
  21.   
  22.             @Override  
  23.             public void run() {  
  24.                 for (;;) {  
  25.                     bChanged = !bChanged;  
  26.                 }  
  27.             }  
  28.         }.start();  
  29.     }  
  30.   
  31. }  


运行后,程序进入死循环了,一直在运行。

 

 

用volatile:

 

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. package com.keyword;  
  2.   
  3. public class TestWithVolatile {  
  4.     private static volatile boolean bChanged;  
  5.   
  6.     public static void main(String[] args) throws InterruptedException {  
  7.         new Thread() {  
  8.   
  9.             @Override  
  10.             public void run() {  
  11.                 for (;;) {  
  12.                     if (bChanged == !bChanged) {  
  13.                         System.out.println("!=");  
  14.                         System.exit(0);  
  15.                     }  
  16.                 }  
  17.             }  
  18.         }.start();  
  19.         Thread.sleep(1);  
  20.         new Thread() {  
  21.   
  22.             @Override  
  23.             public void run() {  
  24.                 for (;;) {  
  25.                     bChanged = !bChanged;  
  26.                 }  
  27.             }  
  28.         }.start();  
  29.     }  
  30.   
  31. }  


程序输出!=,然后马上退出。

 

但是,很多情况下,用不用volatile,感觉不出什么区别,什么时候要用volatile呢?看看JDK里使用volatile的类。

比如java.util.regex.Pattern里的变量:

 

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. private transient volatile boolean compiled = false;  


还有,java.lang.System的变量:

 

 

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. private static volatile Console cons = null;  


一般就是初始化的时候,需要用到volatile。

 

java.util.Scanner里的变量,如:

 

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. private static volatile Pattern boolPattern;  
  2. private static volatile Pattern separatorPattern;  
  3. private static volatile Pattern linePattern;  


初始化boolPattern的代码:

 

 

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. private static Pattern boolPattern() {  
  2.         Pattern bp = boolPattern;  
  3.         if (bp == null)  
  4.             boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,  
  5.                                           Pattern.CASE_INSENSITIVE);  
  6.         return bp;  
  7. }  

 

 

上面的情况,可以使用synchronized来对boolPattern加锁,但是synchronized开销比volatile大,volatile能够胜任上面的工作。

 

volatile不保证原子操作,所以,很容易读到脏数据。

 

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。 

 

参考:

http://sudalyl.blog.163.com/blog/static/1018092742010925901769/

 

REFS:http://blog.csdn.net/feier7501/article/details/20001083


http://www.niftyadmin.cn/n/4235266.html

相关文章

hyperv虚拟机上虚拟机的cpu个数问题

虚拟机支持的内存容量最多达64G,虚拟机支持的vcpu个数最多为4个(如果你虚拟机是WIN2008最多可以4个,如果是win2003最多2个(这里其实是表示微软支持的个数,你也可以通过别的技术手段可以支持4个)&#xff0c…

(转)为什么volatile不能保证原子性而Atomic可以?

在上篇《非阻塞同步算法与CAS(Compare and Swap)无锁算法》中讲到在Java中long赋值不是原子操作,因为先写32位,再写后32位,分两步操作,而AtomicLong赋值是原子操作,为什么?为什么volatile能替代简单的锁&am…

杂文语录积累(二)

1.不要说什么不想谈,没感觉就是硬道理; 2.没有放不下的事,只有放不下的人; 3.我们不可能在一起一辈子,但我们可以把在一起变的久一点。 4.一直记得一句话:打电话的时候记得微笑,对方听得见。可是…

(转)ConcurrentHashMap分段与锁的学习总结

现阶段的学习策略是理解和实践这些知识点,并没有深入分析其原理,但确实精读了许多关于这个主题基础性的资料让我很受益(见参考资料)。 哈希表基础 1.哈希表是基于数组的数据结构 2.通过对关键字的哈希运算实现元素的快速定位 3.哈…

[转]JDK Logging深入分析

2019独角兽企业重金招聘Python工程师标准>>> 日志输出是所有系统必备的,很多开发人员可能因为常常使用log4j而忽视了JDK logging模块,两者之间是否有联系?是怎样的联系?JDK logging处理细节是怎么样的?本周…

CAP理论以及Eventually Consistent (最终一致性)解析(转)

1 CAP理论简介10年前,Eric Brewer教授指出了著名的CAP理论,后来Seth Gilbert 和 Nancy lynch两人证明了CAP理论的正确性。CAP(Consistency,Availability,partition tolerance)理论告诉我们,一个分布式系统不可能满足一致性&#x…

[转载] 大道至简:软件工程实践者的思想——第七章 从编程到工程

作者:周爱民 来源:http://blog.csdn.net/aimingoo 转载于:https://www.cnblogs.com/6DAN_HUST/archive/2012/06/15/2551519.html

(转)如何正解决库存超卖问题 --乱

一般电子商务网站都会遇到如团购、秒杀、特价之类的活动,而这样的活动有一个共同的特点就是访问量激增、上千甚至上万人抢购一个商品。然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超买,以防止造成不必…