`
HelloSure
  • 浏览: 310851 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

说说volatile关键字

阅读更多
Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
而volatile关键字就是提示JVM:(这就是volatile的原理)对于这个成员变量不能保存它的私有拷贝(在线程栈),而应直接与共享成员变量(在主存中)交互。
(打个广告,有兴趣的童鞋可以去看看http://hellosure.iteye.com/blog/1121157中有JMM的详细介绍)
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

使用volatile的目的
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低,这是volatile的优点),而且其使用也更容易出错(这是缺点)。
首先考虑一个问题,为什么变量需要volatile来修饰呢?
要搞清楚这个问题,首先应该明白计算机内部都做什么了。比如做了一个i++操作,计算机内部做了三次处理:读取-修改-写入。
同样,对于一个long型数据,做了个赋值操作,在32系统下需要经过两步才能完成,先修改低32位,然后修改高32位。
假想一下,当将以上的操作放到一个多线程环境下操作时候,有可能出现的问题,是这些步骤执行了一部分,而另外一个线程就已经引用了变量值,这样就导致了读取脏数据的问题。
通过这个设想,就不难理解volatile关键字了。
另外,volatile可以用在任何变量前面,但不能用于final变量前面,因为final型的变量是禁止修改的。也不存在线程安全的问题。

volatile可以用更低的代价替代同步,那么为什么代价更低?
同步的代价, 主要由其覆盖范围决定, 如果可以降低同步的覆盖范围, 则可以大幅提升程序性能.
而volatile的覆盖范围仅仅变量级别的. 因此它的同步代价很低。

volatile与synchronized比较?
volatile 变量可以被看作是一种“程度较轻的synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。
什么意思呢?看看下面这个例子:

比如volatile变量失效的一中情况:http://caoruntao.iteye.com/blog/658074
声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式n++;不是原子操作
这同时也说明了为什么说volatile容易出错,因为volatile仅仅能保证变量可见性, 无法保证原子性。因此volatile运算有可能存在脏数据问题。
虽然增量操作(n++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)
解决这个问题的方法:一是上文给出的synchronized同步方式,但是这显然违背了使用volatile的初衷。另一种是采用CAS非阻塞算法(打个广告在http://hellosure.iteye.com/blog/1126541介绍ConcurrentLinkedQueue中有详细介绍,有兴趣可以看看)

正确使用volatile 的模式
很多并发性专家事实上往往引导用户远离 volatile 变量,因为使用它们要比使用锁更加容易出错。然而,如果谨慎地遵循一些良好定义的模式,就能够在很多场合内安全地使用 volatile 变量。要始终牢记使用 volatile 的限制 —— 只有在状态真正独立于程序内其他内容时才能使用 volatile —— 这条规则能够避免将这些模式扩展到不安全的用例。
具体的使用模式请参考http://www.ibm.com/developerworks/cn/java/j-jtp06197.html,这是篇很好的文章,建议仔细看看
1
3
分享到:
评论

相关推荐

    深入理解JAVA内存模型(高清完整版)

    再来说说volatile关键字。volatile是Java中的一种轻量级同步机制,它能够保证共享变量的可见性,但不保证原子性。当一个变量被声明为volatile时,每次修改都会立即刷新到主内存,其他线程可以立即看到修改。但是,...

    C#多线程编程中的锁系统(二)

    简单来说: volatile关键字是告诉c#编译器和JIT编译器,不对volatile标记的字段做任何的缓存。确保字段读写都是原子操作,最新值。 这不就是锁吗? 其这货它根本不是锁, 它的原子操作是基于CPU本身的,非阻塞的。 ...

    招银网络java科技笔试题-mianjing:mianjing

    volatile关键字?volatile修饰数组?修饰对象? 找两条链表公共节点? 如何判断循环链表? mysql索引?B+数搜索复杂度? mysql事务? 进程线程区别? 进程池? 进程几种状态?调用sleep方法进程是什么状态? 单线程...

    Java面试宝典

    volatile关键字是否能保证线程安全?** - `volatile`关键字可以确保变量的可见性和禁止指令重排,但不能保证原子性操作。对于复合操作如`i++`,使用`volatile`并不能保证线程安全。 **5. Java有没有goto?** - ...

    软件开发技术面试常见题目

    1. transient 和 volatile 是 Java 关键字吗? 2. 抽象类和接口有什么区别? 3. 能说一下 Java 的反射机制吗? 4. 在 Java 中怎样实现多线程? 5. 你用过哪种设计模式? 6. 请说一下 MVC 架构。 7. 如果类 a 继承类 ...

    Java面试宝典2013_PDF版.pdf

    同步实现方法包括使用synchronized关键字、使用Lock接口、使用volatile关键字等。 51. 启动一个线程是用run()还是start()? 启动线程应该使用start()方法,它会创建新的线程执行run()方法。 52. 当一个线程进入一...

    java面试宝典

    - **同步方式:** synchronized关键字、Lock接口、volatile关键字等。 **50. 用户线程与守护线程的区别?** - **用户线程:** 由程序员创建并控制。 - **守护线程:** 为其他线程提供服务,JVM退出时会自动终止。 **...

    java面试必会200题.docx

    22. **简单说说你了解的类加载器。是否实现过类加载器** - 类加载器负责将Java类加载到JVM中。主要有以下几种:Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader、自定义ClassLoader。 - 实现类...

    百度2019年最新面试题库

    #### 简单说说你了解的类加载器。是否实现过类加载器 类加载器是Java虚拟机的一部分,负责将字节码加载到内存中,并转换为可执行的类。Java中有多种类加载器,包括Bootstrap ClassLoader、Extension ClassLoader和...

    从0到C ——Linux 上 C 语言编程入门

    9. **易失变量**:使用`volatile`关键字声明的变量,其值可能在任何时候被外部因素更改。 10. **受限变量**:使用`restrict`关键字声明的指针,确保该指针是唯一访问该内存区域的方式。 11. **动态内存**:使用`...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【多线程】Volatile的理解 82 【*多线程】synchronized底层如何实现的? 82 【多线程】Callable 和 Runnable接口 82 【多线程】Java四种线程池的创建方法 83 【多线程】线程池原理和运行机制 83 【多线程】线程池对...

    Java后端技术面试汇总-2019

    - **说说线程安全问题**:在多线程环境下,确保数据的一致性和正确性。 - **重入锁的概念**:支持同一个线程多次获得同一把锁。 - **产生死锁的四个条件**:互斥条件、请求与保持条件、不剥夺条件、循环等待条件。...

Global site tag (gtag.js) - Google Analytics