Java中synchronized与volatile的区别与联系

在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 cached variables synchronized 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. Atomic get-set of volatiles possible in Java 5.


参考文献:

https://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#volatile


你可能感兴趣的:(Java中synchronized与volatile的区别与联系)