1.volatile和synchronized 语句块都可以保证变量的可见性。可见性:也就是当其他线程修改了共享变量,当线程执行读操作时都能拿到最新的变量内容(也就是从主存中拿,不会从工作内存中拿).这里的工作内存指的是JVM编译器会自身优化,JIT 编译器会将成员变量的值缓存至自己工作内存中的高速缓存中,减少对主存中变量的访问,提高效率.
举个例子:
static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(run){
}
});
t.start();
sleep(1000);
run = false;
}
线程将不会停止:
2.volatile不能保证原子性,而synchronized是可以保证原子性。
由于JVM 会在不影响正确性的前提下,可以调整语句的执行顺序,也就是指令重排.这就导致指令在执行的过程中,JVM根据自身优化导致指令执行的顺序发生变化.那么如何保证指令重排导致的一些程序执行过程中的问题呢?
3.volatile可以保证有序性也就是禁用指令重排.而synchronized中变量的指令操作必须都在同步代码块时才能保证指令有序性,不能脱离同步代码块的"保护"
常见这种情况是不能保证有序性的
public static Singleton getInstance(){
if (instance == null){ //读操作脱离了同步代码快
synchronized (Singleton.class) {
if (instance == null) {
return new Singleton();
}
}
}
return instance;
}