并发编程三个特性:
原子性、有序性、可见性
原子性
volatile无法保证原子性。
synchronized是排它锁,被synchronzied修饰的代码不能被打断,所以具有原子性。
有序性
volatile禁止JVM编译器及处理器对volatile修饰的指令重排序。
synchronzied是以程序的串行化执行来保证顺序性的,synchronized代码块中的代码是可以重排序的。
可见性
volatile使用机器指令lock将修改后的工作内存中的数据强制刷新到主内存,并迫使其他线程的工作内存数据失效,从而保证可见性。
synchronized借助jvm指令monitorenter和monitorexit使代码串行化,在monitorexit时所有共享资源都将刷新的到主内存,从而保证可见性。
Violated
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
- 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这个新的值对其他线程来说是可见的。
- 禁止进行指令重排序。
volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中获取。
Synchronized
锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
区别对比
- volatile仅能使用在变量级别,synchronized则可以使用在变量、方法和类级别。
- volatile仅能实现变量的修改可见性,并不能保证原子性;synchronized则可以既保证变量的修改可见性和原子性。
- volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
- volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。