现在的位置: 首页 > 综合 > 正文

JAVA volatile关键字

2013年11月29日 ⁄ 综合 ⁄ 共 1753字 ⁄ 字号 评论关闭

     Java中volatile关键字原义是“不稳定、变化”的意思,那么在java语言中,volatile是什么意思呢?

     volatile,在Java中用来修饰变量,那是为什么呢?volatile是告诉jvm,这个变量不能被私自占有使用,下面就解释一下为什么这么说吧!

     大家都知道,在java中,除了long和double的操作,对基本类型的操作是原子性的,那还为什么使用valotile关键字呢,因为随着jvm的优化和成熟,为了提高多线程的效率,允许每个线程在工作内存保存变量的拷贝进行操作,这就很容易出现数据不一致,所以volatile就强制是多核或多线程必须从主存中读写变量,保证变量的一致性

     由于比起synchronized,volatile关键字的覆盖范伟更小,只是修饰的变量,所以效率就比前者高,但是,它是存在问题的,不能保证“线程写的合理”,解释如下:写的不合理,是可能存在竞争条件,而出现操作与设想结果不同。volatile变量在并发下不安全

     假如,有100个线程正在对一个i变量惊醒i++操作,那么结果一定是100么,可能<100的,比如一个线程a读到的是i=3,几乎同时(a没有修改i),另一个线程也读到3,那么结果,两次相加就得到了i=4,而不是5,详细看看操作系统同步就知道了。

     volatile关键字有什么用?恐怕比较一下volatile和synchronized的不同是最容易解释清楚的。volatile是变量修饰符,而synchronized则作用于一段代码或方法;看如下三句get代码:

     int i1;                  int geti1() {return i1;}

     volatile int i2;         int geti2() {return i2;}

     int i3; synchronized     int geti3() {return i3;}


  geti1()得到存储在当前线程中i1的数值。多个线程有多个i1变量拷贝,而且这些i1之间可以互不相同。换句话说,另一个线程可能已经改变了它线程内的i1值,而这个值可以和当前线程中的i1值不相同。事实上,Java有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程可以有它自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的i1值是1,线程1里的i1值是2,线程2里的i1值是3——这在线程1和线程2都改变了它们各自的i1值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。

  而geti2()得到的是“主”内存区域的i2数值。用volatile修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的,volatile修饰的变量存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。

  既然volatile关键字已经实现了线程间数据同步,又要synchronized干什么呢?呵呵,它们之间有两点不同。首先,synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是,synchronized也同步内存:事实上,synchronized在“主”内存区域同步整个线程的内存。因此,执行geti3()方法做了如下几步:

1. 线程请求获得监视this对象的对象锁(假设未被锁,否则线程等待直到锁释放)

2. 线程内存的数据被消除,从“主”内存区域中读入(Java虚拟机能优化此步。。。[后面的不知道怎么表达,汗])

3. 代码块被执行

4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过geti3()方法不会改变变量值)

5. 线程释放监视this对象的对象锁

  因此volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源

抱歉!评论已关闭.