java 缓存_Java多线程——CPU缓存原理和缓存一致性问题

1c473e6c6db5ff541260f150df8b6110.png

说起Java中的多线程,就不得不说volatile关键词

volatile关键词执行修饰变量和实例变量,不能修饰方法参数,局部变量和实例常量。

volatile是Java提供的一种轻量级的同步机制,在并发编程中,它是担任了重要的角色。同synchronized相比(synchronized通常称为重量级锁),volatile更轻量级。

想要了解votatile的来龙去脉,就必须了解CPU缓存模型和java内存模型,本文介绍前者。

众所周知,计算机所有的运算操作都是在cpu寄存器来完成的,运算操作无非就是数据的读取和写入操作,但CPU能访问的数据只能是计算机内存(RAM),虽然相比于普通硬盘固态硬盘,RAM的速度远超这两者,但比起CPU的处理速度来说,这之间的差距可达数千倍。

举个简单的例子,随着光纤的普遍接入,网络速度大大提高,可不管下载速度如何提高,它的上限都受制于硬盘的写入速度,就算下载速度超过了10GB/s,可固态硬盘写入速度撑死也只能达到它的十分之一。

CPU也一样,由于运算速度和内存访问速度上面的不对等,导致CPU资源会受到极大的限制,于是就有在CPU主存和内存之间增加了缓存的设计。

c15103f4eb616bb2eb31058937b0e652.png

看图中I9 9900K的参数,现在的缓存可以增加到3级。

在程序的运行中,会将运算所需要的数据复制一份到CPU缓存中,这样CPU就可以直接对缓存中的数据进行运算,当运算结束后,将缓存中的数据刷新到内存中,依靠这样的方式,极大提高了CPU的吞吐量。

在提高了吞吐量的同时,也出现了另一个问题,缓存不一致、

试想有一段运算操作:i++

  1. 读取i的值到cpu cache中
  2. 对i进行加1操作
  3. 将结果保存到cpu cache中
  4. 运算完成,将数据刷新到内存中

这里就存在和java一样的多线程问题,在两个线程同时对i进行操作的时候,每个线程都有自己的工作内存,变量i会在多个线程的本地内存中都保存一个副本,假设i值为1,在同一时间的两个线程读取i的值保存在cpu cache中,经过运算后再写入内存,但i再经过两次自增后,最后写入内存的值还有可能是2。

为了解决这个问题,通常有两种办法:

  • 加锁的方式
  • 缓存一致性协议

第一种方式是一种悲观的方式,只有一个cpu能抢到锁进行运算,而其他cpu就进入阻塞状态。这种方式的效率低下,所以就有了第二种方式。

缓存一致性协议的大致思想是:

如果cpu在操作数据的时候,发现数据是一个共享变量(其他cache也保存了副本),就进行如下操作:

  1. 读取操作:不做任何处理,只是将cache的数据读取到寄存器。
  2. 写入操作:发送一个信号通知其他cpu这个变量我已经改过了,设置为无效变量,其他cpu在进行操作的时候就不得不重新读取一次数据再进行操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值