synchronized实现可见性对比volatile

版权声明:http://blog.csdn.net/jarwis https://blog.csdn.net/jarwis/article/details/82669117

最近花时间研究了下,如有不正确的地方,欢迎大家批评指正,谢谢。

首先先介绍一下JMM(JAVA内存模型),上图:

java内存模型的工作原理如上图所示,一些被定义的变量都存放在主内存中,当一个线程想要修改一个变量的值时,那么这个变量会从主内存中拷贝到线程的工作内存(CPU缓存)中。之后线程对变量值做了更改,又会重新拷贝回主内存中。大家通过描述也可以看出来这些操作是分步执行的,这样就无法保证可见性和原子性。对于这种情况java也给出了很多解决办法,今天跟大家分享一下我对synchronized以及volatile的理解。

大家知道synchronized是通过加互斥锁来实现原子性的,JMM关于synchronized的两条规定:

  1. 线程解锁前,必须把共享变量的最新之刷新到主内存中
  2. 线程加锁前,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要时同一把锁)

我来简单描叙一下线程执行互斥代码的过程:

  1. 获得互斥锁
  2. 清空工作内存
  3. 从主内存拷贝变量的最新副本到工作内存
  4. 执行代码
  5. 将更改后的共享变量的值刷新到主内存
  6. 释放互斥锁

synchronized从而实现类原子性,也具备内存可见性。

这里多说一下Lock,其实原理跟synchronized类似,但是比synchronized更加灵活,我们会在下一篇博客中详细探讨synchronized的缺陷以及Lock的基本用法。

volatile是如何实现内存可见性的呢?

深入来说:是通过加入内存屏障和禁止重排序优化来实现的。(重排序指单线程中在保证执行结果不变的前提下java虚拟机为了提升处理速度可能会将指令重排,达到最合理化)

扫描二维码关注公众号,回复: 3725390 查看本文章
  • 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令
  1. 改变线程工作内存中的volatile变量副本的值
  2. 将改变后的副本的值从工作内存刷新到主内存
  • 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令
  1. 从主内存中读取volatile变量的最新值到线程的工作内存中
  2. 从工作内存中读取volatile变量的副本

简单来说:volatile变量在每次被线程访问时,都强迫从sy主内存中重读变量的值,而当该变量发生变化时,又会强迫线程将最新的值刷新到主内存。这样在任何时刻,不同的线程总能看到该变量的最新值。从而保证了变量的内存可见性。

synchronized和volatile的比较

  1. volatile不需要加锁,比synchronized更加轻量级,不会阻塞线程
  2. 从内存可见性讲,volatile读相当于加锁,volatile写相当于解锁
  3. synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性

猜你喜欢

转载自blog.csdn.net/jarwis/article/details/82669117
今日推荐