既然synchronized是"万能"的,为什么还需要volatile呢?

synchronizedvolatile两个关键字是Java并发编程中经常用到的两个关键字。我们知道synchronized可以保证并发编程中不会出现原子性、可见性和有序性问题,而volatile只能保证可见性和有序性,那么,既然有了synchronized,为什么还需要volatile

  1. Java中为了解决多线程中存在的原子性、可见性和有序性问题,提供了一系列和并发处理相关的关键字,例:synchronized、volatile、final、concurren包等。

  2. synchronized通过加锁的方式,使得其在需要原子性、可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的。的确,大部分并发控制操作都能使用synchronized来完成。

  3. volatile通过在volatile变量的操作前后插入在JVM虚拟机内存屏障(JMM)的方式,保证了变量在并发场景下的可见性和有序性(操作系统的实现机制,汇编指令lock addl $0x0,(%rsp)以及缓存一致性协议(MESI))。

  4. volatile关键字是无法保证原子性的,而synchronized通过jvm层指令monitorentermonitorexit两个指令,可以保证被synchronized修饰的代码在同一时间只能被一个线程访问,即可保证不会出现CPU时间片在多个线程间切换,即可保证原子性。

  5. synchronized实现的锁本质上是一种阻塞锁,也就是说多个线程要排队访问同一个共享对象。而volatile是Java虚拟机提供的一种轻量级同步机制,他是基于内存屏障实现的。说到底,他并不是锁,所以他不会有synchronized带来的阻塞和性能损耗的问题。

  1. 在一般的程序中只要加上了synchronized就不需要再加上volatile,但是在单例模式则需要。这是因为为了防止指令重排

注意:

  1. 本文中强调了JVM层面指令与操作系统层面的指令,请读者不要混淆。
  2. 在操作系统中带有lock前缀的的指令在多核处理器会发生两件事:
    2.1 将当前处理器缓存行的数据写回到系统内存里面去
    2.2 这个写回内存的操作会使其他CPU缓存行的数据无效

本作品采用《CC 协议》,转载必须注明作者和本文链接
jzhao
Barnett_fly
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!