`
wezly
  • 浏览: 487275 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

关于volatile变量的理解

阅读更多

前些日子在看些多线程方面的资料,当我看到对volatile这个关键字的解释的时候,让我出现了一些困惑!

 

在某些书籍中说

写道
'在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步.当你定义long或double变量时,如果使用volatile关键字,就会获得(简单的赋值与返回操作的 )原子性'
 

 然而一篇IBM技术论坛上的文章似乎又有不同的观点(http://www.ibm.com/developerworks/cn/java/j-jtp06197.html)

Java代码 复制代码
  1. volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。  
volatile变量具有 synchronized 的可见性特性,但是不具备原子特性。

 两段文字粗略一看,似乎搞得人晕头转向了,更加难以理解volatile的特性了!

但是请注意第一段文字中被标红的一段"简单的赋值与返回操作的"原子性",这里似乎说明这种原子性不可靠!因为long和double类型的长度都是64位的,由于jvm的原因可能造成撕扯现象.这里的简单原子性应该是保证变量不会被撕扯得面目全非吧!

有人对volatile做如下整理(http://hi.baidu.com/lifa868/blog/item/22bc7718926ad772dbb4bd0e.html):

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

Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。

这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。

而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

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

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

 

后来在一篇对C#中volatile相关文章中看到这样一句话(http://www.cnblogs.com/lucifer1982/archive/2008/03/23/1116981.html):

写道
到这里,我们已经知道volatile提供的同步机制还不足以能够实现线程安全计数器。因为计数器虽然简单,却是三种操作的组合,如果多线程试图进行增量操作,很可能会丢失其更新值。

 

还有这样一种理解,volatile在增量操作时已经失去了原子性,如i++其实是i=i+1,这种情况下我们就认为原子性将丢失。而在i=m的情况下是可以保证原子性的!

这样一来是不是可以做出以下理解:

   java中有主内存和工作内存之分,当变量变申明volatile之后.

1.所有的读写操作都直接从主内存进行.

2.每次对变量的修改强行回写到主内存中,供其他线程共享!

最后想做一个假设,以说明自己对上诉观点的理解:

Java代码 复制代码
  1. static volatile int i=0;   
  2. static void add(){   
  3.     i++;   
  4. }   
  5. .......  
static volatile int i=0;
static void add(){
    i++;
}
.......

在多线程并发访问add()方法的时候,T1线程和T2线程同时进入add(),由于{i++}=={i=i+1}其实是先从主内存中读取i,而后对i进行增量修改,最后回写主内存。那就有可能出现这样的情况:在T1进入后读取的i=9,T2同时也读取的也是9,T1线程操作后i=10然后回写主内存,T2也同时完成操作i=10也回写主内存,那T2的回写值是不是就覆盖了T1的回写值,这也就是上述中所提及的“如果多线程试图进行增量操作,很可能丢失其更新值”。

由于对jvm内存设计不是非常熟悉,不清楚实际jvm中对volatile是否在内存也是这样操作的,希望大家能提供更多资料以便相互交流,探讨!

分享到:
评论

相关推荐

    volatile 变量的说明

    volatile变量在编程语言中,尤其是Java和C/C++中,是一种特殊的标识符,用于指示编译器该变量的值可能在编译器不知情的情况下发生变化。这个关键字的主要作用是告诉编译器不要对这个变量进行优化,每次使用时都需要...

    stm32 volatile变量的正确使用

    ### STM32中Volatile变量的正确使用 #### 概述 在嵌入式系统编程中,`volatile`关键字的正确使用对于确保程序的稳定性和可靠性至关重要。它主要用于标记那些可能在程序运行过程中被外部因素(如硬件中断、多线程...

    java入门教程:数据类型_Java理论与实践如何正确使用Volatile变量.docx

    ### Java入门教程:数据类型与正确使用Volatile变量 #### 概述 在Java编程语言中,`volatile`关键字提供了一种轻量级的同步机制,用于确保共享变量的可见性和一定程度上的线程安全性。相比于传统的锁机制如`...

    深入探讨Java多线程中的volatile变量共6页.pd

    本资料《深入探讨Java多线程中的volatile变量》将带你深入理解这个概念,全面解析其工作原理和实际应用。 volatile关键字在Java中主要用于解决多线程环境下的可见性和有序性问题。它确保了被volatile修饰的变量对...

    Java并发编程(5)volatile变量修饰符-意料之外

    在实际开发中,理解`volatile`的局限性至关重要。错误地依赖`volatile`可能导致难以调试的并发问题。例如,假设你用`volatile`维护一个状态变量,而其他线程依赖这个状态进行后续操作,如果没有适当的同步措施,可能...

    volatile变量的的概念和使用

    在C语言编程中,`volatile`是一个非常重要的关键字,它用于修饰变量,向编译器传达特殊的指示。...理解和正确使用`volatile`是成为一名合格的C语言程序员,特别是在嵌入式和系统级编程领域中的必备技能。

    Linux C中多线程与volatile变量

    在Linux C编程中,多线程编程是一种常见的并发执行方式,允许程序同时执行多个任务,提高系统的效率...理解`volatile`的关键在于它是如何影响编译器的行为,以及如何在多线程环境中正确地使用它来实现有效的数据同步。

    Java Volatile 变量详解及使用方法

    Java中的`volatile`关键字是用来修饰变量的,它主要用于解决多线程环境下的数据同步问题。在Java语言中,`volatile`变量提供了一种轻量级的同步机制,它确保了共享变量的可见性和有序性,但并不保证原子性。 **可见...

    Volatile详解,深入学习Volatile

    - 防止编译器优化:编译器通常会优化掉被认为不变的变量的读取,但volatile变量告诉编译器不要做这样的优化,每次使用时都从内存中读取。 - 多线程同步:在多线程环境中,当一个线程修改了volatile变量,其他线程...

    Java并发编程之volatile变量介绍

    即当一个线程修改了volatile变量,其他线程能够立即看到这个变化,无需通过缓存或内存屏障来同步。这是因为volatile变量不会被存储在处理器的寄存器或本地线程存储中,而是直接在主内存中操作。因此,每次读取...

    深入理解 volatile 关键字.doc

    但是这并不意味着对volatile变量的操作是线程安全的,因为有可能在读取到变量之后,又有其他线程对变量进行修改了。 例如,下面代码发起了20个线程,每个线程对race变量进行1万次自增操作。如果这段代码能够正确...

    深入探讨Java多线程中的volatile变量

    Java多线程中的volatile变量是...理解和正确使用volatile变量,可以有效地提高多线程程序的性能和正确性。然而,需要注意的是,它不能完全替代锁或其他同步手段,开发者需要根据具体的应用场景选择合适的并发控制策略。

    从汇编角度理解volatile

    通常的理解是,volatile告诉编译器不要对某个变量进行优化,每次读取该变量时都直接从内存中获取,而不是使用寄存器中的副本。这样做是为了确保在多线程环境下或者有外部因素(如硬件设备)影响变量时,能正确地反映...

    volatile源码分析1

    x86处理器有L1、L2、L3缓存,以及多核之间的缓存一致性协议(如MESI协议),这些机制共同保证了多核环境下volatile变量的正确传播和一致性。 总结来说,volatile关键字通过禁止指令重排序和提供内存可见性,确保了...

    C语言中关于关键字volatile的用法

    最后,回到示例代码中的问题,使用volatile变量时,编译器生成的代码会考虑到变量可能在每次读取时都被修改的可能性。这就解释了为什么在计算指针所指向数据的平方时,不能简单地假设指针指向的数据在两次读取间不会...

    聊聊并发(一)深入分析Volatile的实现原理

    1. **内存可见性**:当一个线程修改了Volatile变量的值,其他线程可以立即看到这个修改。这意味着Volatile变量在被修改后,无需额外的同步操作,其他线程就能获取到最新的值。 2. **禁止指令重排序**:编译器和...

    volatile的使用1

    这是因为volatile变量的修改会直接写回主内存,其他线程在读取时会从主内存中获取最新值,而不是从各自的CPU缓存中读取,从而确保了数据的一致性。相比非volatile变量,线程可能会持有旧的副本,而无法感知到其他...

    const和volatile分析

    在C++编程语言中,`const`和`volatile`是两个非常重要的关键字,它们用于修饰变量,赋予变量特殊的属性。这两个关键字在理解程序的行为、内存模型以及多线程编程中起到至关重要的作用。在此,我们将深入探讨`const`...

    volatile用法

    `volatile`关键字在C语言中是一个非常重要的概念,主要用于处理多线程环境或者与硬件交互时的内存可见性问题。它的主要作用是确保对变量的修改能够立即...理解和正确使用`volatile`对于编写健壮的并发代码至关重要。

Global site tag (gtag.js) - Google Analytics