一 使用上的区别
-
volatile 关键字只能用于修饰实例变量或者类变量,不能用于修饰方法、方法参数、局部变量和常量等。
-
synchronized 关键字不能用于对变量的修饰,只能用于修饰方法或者语句块。
-
volatile 修饰的变量可以为 null,synchronized 关键字同步语句块 monitor 对象不能为 null。
二 对原子性的保证
-
volatile 无法保证原子性。
-
由于 synchronized 是一种排他机制,因此被 synchronized 关键字修饰的同步代码块是无法被中途打断的,因此能够保证原子性。
三 对可见性的保证
-
两者都可以保证共享资源在多线程间的可见性,但是实现机制完全不一样。
-
synchronized 借助 JVM 指令 monitor enter 和 monitor exit 对通过排他方式使得同步代码串行化,在 monitor exit 时所有共享资源都将会被刷新到主内存中。
-
volatile 使用机器指令的方式迫使其他线程工作内存中的数据失效,不得不到主内存中进行再次加载。
四 对有序性的保证
volatile 关键字禁止 JVM 编译器以及处理器对其进行重排序,所以它能够保证有序性。
synchronized 关键字所修饰的同步方法可以保证顺序性,但是这中顺序性是以程序串行化执行换来的,在 synchronized 关键字所修饰的代码块中代码指令也会发生指令重排序的情况,比如:
synchronized(this){
int x = 10;
int y = 20;
x++;
y = y+1;
}
x 和 y 谁先定义以及谁先进行运算,对程序来说没有任何影响,另外 x 和 y 之间也没有依赖关系,但是由于 synchronized 关键字同步的作用,在 synchronized 的作用域结束时 x 必定是 11,y 必定是21,也就是说达到了最终的输出结果和代码编写顺序一致性。
五 其他
- volatile 不会使线程陷入阻塞。
- synchronize 关键字会使线程进入阻塞状态。