Java
语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量
的原始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而volatile
关键字就是提示JVM
:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile
。当要访问的变量已在synchronized
代码块中,或者为常量时,不必使用。
由于使用volatile
屏蔽掉了JVM
中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。 就跟C
中的一样 禁止编译器进行优化.
注意:如果给一个变量加上volatile修饰符,就相当于:每一个线程中一旦这个值发生了变化就马上刷新回主存,使得各个线程取出的值相同。编译器不要对这个变量的读、写操作做优化。但是值得注意的是,除了对long
和double
的简单操作之外,volatile
并不能提供原子性。
所以,就算你将一个变量修饰为volatile
,但是对这个变量的操作并不是原子的,在并发环境下,还是不能避免错误的发生!
synchronized
为一段操作或内存进行加锁,它具有互斥性。当线程要操作被synchronized
修饰的内存或操作时,必须首先获得锁才能进行后续操作;但是在同一时刻只能有一个线程获得相同的一把锁(对象监视器),所以它只允许一个线程进行操作。
它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。synchronized(this)
同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。object
的一个synchronized(this)
同步代码块时,另一个线程仍然可以访问该object
中的非synchronized(this)
同步代码块。object
的一个synchronized(this)
同步代码块时,其他线程对object
中所有其它synchronized(this)
同步代码块的访问将被阻塞。volatile
是变量修饰符,而synchronized
则作用于一段代码或方法。volatile
只是在线程内存和“主”内存间同步某个变量的值;而synchronized
通过锁定和解锁某个监视器同步所有变量的值。显然synchronized
要比volatile
消耗更多资源。