本文共 1683 字,大约阅读时间需要 5 分钟。
在Java多线程编程中,synchronized是非常常用的关键字,而volatile关键字比较罕见。
volatile关键字用以避免因缓存(caching)或重排(reordering)而导致当前线程读取过时的数据。任何时候,线程读取的都是主线程内存中的最新数据。
在Java 1.5之前,多线程对volatile变量的访问是无法被重排的,但是对非volatile变量的访问是被重排的。这使得多线程在同时访问volatile变量和非volatile变量时,volatile变量无法被用作多线程的信号条件。因为虽然保证了volatile变量是最新的,但是不能保证非volatile变量是最新的。
从Java 1.5开始,volatile关键字被赋予了新的特性,更加接近synchronized的严格。对volatile变量的读操作就类似于对内存访问的加锁,对volatile变量的写就类似于对内存访问的释放锁。
由于对volatile变量和非volatile变量之间的重排设置了更加严格的限制,虽然volatile变量仍然无法被重排,但是对非volatile变量的重排也不那么容易了,从而使得volatile变量有可能作为信号条件。示例如下:
class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { //uses x - guaranteed to see 42. } }}说明:由于在writer()方法中修改volatile变量v的同时,也修改了非volatile变量x,所以在Java 1.5中,对于执行reader()方法的线程来说,volatile变量v和非volatile变量x的最新值都是可见。而在Java 1.5之前,是无法保证非volatile变量x是最新值的。
当然,这也是有条件的,那就是多线程之间设置了准确的happens-before关系,即写入线程与读取线程操作的是同一个volatile变量v,即加的锁(类似锁但实际不是锁)与释放的锁匹配。
synchronized与volatile的主要区别有2点:
首先,从用法上,synchronized往往作用于方法或代码块,而volatile往往修饰变量。
其次,从实现机制上,synchronized是利用锁实现互斥访问。而volatile没有利用锁,而是利用内存共享,即volatile变量只在主线程中有一份,所有其他线程都共享这一份,因而一个线程对内存执行了写操作,所有其他线程立刻就能够读到最新的数据。
synchronized与volatile的对比:
Characteristic | Synchronized | Volatile |
---|---|---|
Type of variable | Object | Object or primitive |
Null allowed? | No | Yes |
Can block? | Yes | No |
All on access? | Yes | From Java 5 onwards |
When synchronization happens | When you explicitly enter/exit asynchronized block | Whenever a volatile variable is accessed. |
Can be used to combined several operations into an atomic operation? | Yes | Pre-Java 5, no. possible in Java 5. |
参考文献:
https://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#volatile
转载地址:http://dnlai.baihongyu.com/