首页 > 代码库 > volatile和synchronized 差别

volatile和synchronized 差别

1、什么是volatile


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


Java语言规范中指出:为了获得最佳速度。同意线程保存共享成员变量的私有拷贝。并且仅仅当线程进入或者离开同步代码块时才与共享成员变量的原始值对照。
这样当多个线程同一时候与某个对象交互时,就必需要注意到要让线程及时的得到共享成员变量的变化。


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


使用建议:在两个或者很多其它的线程訪问的成员变量上使用volatile。

当要訪问的变量已在synchronized代码块中。或者为常量时。不必使用。


因为使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比較低。因此一定在必要时才使用此keyword。 


2、volatile和synchronized 差别

  1. volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,须要从主存中读取,synchronized则是锁定当前变量,仅仅有当前线程能够訪问该变量,其它线程被堵塞住.
  2. volatile仅能使用在变量级别,synchronized则能够使用在变量,方法.
  3. volatile仅能实现变量的改动可见性,但不具备原子特性,而synchronized则能够保证变量的改动可见性和原子性.
  4. volatile不会造成线程的堵塞,而synchronized可能会造成线程的堵塞.
  5. volatile标记的变量不会被编译器优化,而synchronized标记的变量能够被编译器优化.


引用:

http://blog.csdn.net/majorboy/article/details/475811

这个可能是最好的对照volatilesynchronized作用的文章了。

volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符。所以我们使用这两种keyword来指定三种简单的存取变量的方式。

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

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

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

geti1()当前线程中马上获取在i1变量中的值。

线程能够获得变量的本地拷贝。而所获得的变量的值并不一定与其它线程所获得的值同样。特别是。假设其它的线程改动了i1的值,那么当前线程获得的i1的值可能与改动后的值有所区别。实际上。Java有一种主内存的机制,使用一个主内存来保存变量当前的正确的值。线程将变量的值复制到自己独立的内存中,而这些线程的内存拷贝可能与主内存中的值不同。

所以实际其中可能发生这种情况。在主内存中i1的值为1。线程1和线程2都更改了i1,可是却没把更新的值传回给主内存或其它线程中,那么可能在线程1i1的值为2,线程2i1的值却为3

还有一方面,geti2()能够有效的从主内存中获取i2的值。一个volatile类型的变量不同意线程从主内存中将变量的值复制到自己的存储空间。因此,一个声明为volatile类型的变量将在全部的线程中同步的获得数据,不论你在不论什么线程中更改了变量,其它的线程将马上得到相同的结果。

因为线程存取或更改自己的数据拷贝有更高的效率,所以volatile类型变量在性能上有所消耗。

那么假设volatile变量已经能够使数据在线程间同步。那么synchronizes用来干什么呢?两者有双方面的不同。

首先。synchronized获取和释放由监听器控制的锁。假设两个线程都使用一个监听器(即同样对象锁)。那么监听器能够强制在一个时刻仅仅有一个线程能处理代码块。这是最一般的同步。

另外。synchronized还能使内存同步。在实际其中。synchronized使得全部的线程内存与主内存同样步。所以geti3()的运行步骤例如以下:

1.    线程从监听器获取对象的锁。(这里如果监听器非锁,否则线程仅仅有等到监听器解锁才干获取对象锁)

2.    线程内存更新全部的变量。也就是说他将读取主内存中的变量使自己的变量保证有效。

(JVM会使用一个“脏”标志来最优化过程。使得只具有“脏”标志变量被更新。具体的情况查询JAVA规范的17.9)

3.    代码块被运行(在这个样例中,设置返回值为刚刚从主内存重置的i3当前的值。

)

4.    不论什么变量的变更将被写回到主内存中。可是这个样例中geti3()没有什么变化。

5.    线程释放对象的锁给监听器。

所以volatile仅仅能在线程内存和主内存之间同步一个变量的值,而synchronized则同步在线程内存和主内存之间的全部变量的值,而且通过锁住和释放监听器来实现。

显然,synchronized在性能上将比volatile更加有所消耗。



volatile和synchronized 差别