聊一聊Volatile 和synchronized

548 阅读2分钟

今天正式开始我的面试之旅,因为自己的工作经历原因,平时很少会用JUC相关的处理。今天虽然也问到了,凭着自己看过几本书经历勉强过关,正如赏金的潜台词一样,好运不会眷顾傻瓜的。结合今天面试问题我们深度剖析一下最常见的问题, Volatile和Synchrnized?

image.png

秉持着体育老师教过我们鲁迅说过:敏而好学,不会就去看书。作为体育课从不逃课的学生来说,肯定听老师的话,我们就揭开这层窗户纸。

JVM的内存模型我们就不在重复说了,可以看我博客前面的文章,那么CPU Cache模型是什么样的呢?

未命名文件 (13).png

缓存中又分L1 L2 L3 我们就不画了,关系不大。为什么在CPU和RAM中出现了一个第三者缓存Cache呢? 这里并不是因为CPU花心,而是为了解决CPU直接访问内存效率低下的问题,程序在运行的过程中,会将运算所需要的数据从主内存中Copy一份到Cache中,这样CPU进行计算的时候就可以直接对Cache中的数据进行读取和写入,当运算结束之后,再将Cache到主内存中,CPU通过直接访问Cache的方式替代直接访问主存的方式。极大提高了CPU的吞吐能力。

CPU和主存之间产生了小三,如何解决CPU的缓存一致性问题呢?

  • 读取主内存的i到CPU Cache中
  • 对i进行加一操作
  • 将结果写回到CPU Cache中
  • 将数据刷新到主内存中

这个场景下两个线程同时操作 i起始为0 ,那么两次自增就会出现结果为1 的情况实际应该是2 解决这个问题我们两种方式去解决:

  • 总线加锁
  • 缓存一致性协议 总线加锁过于悲观,我买了一个8核CPU在多线程下你非要我用单核,我的钱又不是大风刮来的 ,怎么可以这样用呢。

缓存一致性最出名的就是Inter的MESI协议。MESI协议保证了每一个缓存中使用的共享变量副本都是一致的,它的大致思想,当CPU在操作Cache的时候,如果发现该变量是一个共享变量,也就是CPU Cache中也存在一个副本会做如下操作

  • 读取操作,不做任何处理,只是将Cache中的数据读取到寄存器中。
  • 写入操作,发出信号通知其他CPU将该变量的Cache line 设置为无效状态,其他的CPU在进行变量读取操作的时候不得不到主内存中再次获取。

未命名文件 (14).png

周六在码 未完待续