Java:缓冲行(cache line)的一些问题

对缓冲行我还有些地方不太理解,
1 缓存一致性下缓冲行失效是不是仅针对volatile,如果不是volatile变量应该不会有这种问题吧?
2 具体实践的时候,什么情况下才进行缓冲行填充?所有高并发情况下成员volatile变量频繁写的类都要进行缓冲行填充吗?都要使用disruptor框架?

阅读 3.9k
2 个回答

准确来说确实不是针对volatile,而是解决了volatile内存可见性带来的false sharing问题的。如果不是volatile这种问题应该不会存在。

具体实践中,也是一般针对基本数据类型的volatile比较合适,因为行缓冲中的cache line的大小一般也就只有64字节而已。

除了disruptor框架,你可以查看hystrix和java8中的Long adder

前几天刚看了几篇相关文章,说一下我的理解吧,权作交流,有不对的地方还请指正。

首先说说我对题目中的几个相关重要概念的理解:

  1. 缓存一致性是指的由于CPU缓存的存在导致的并发访问时多个CPU缓存中的数据不一致的问题。
  2. volatile关键字是在java中使用内存屏障来解决缓存一致性问题的方式。
  3. 缓存行是CPU本身优化缓存使用效率的一种机制,也即从内存到CPU缓存的数据操作是以行为单位的,这一行中可能包含多个变量,而由于该机制,结合MESI协议,当并发操作同一行的不同变量的时候就会产生伪共享问题,也即对不同变量的操作却产生了竞争问题有了同步锁,这种不必要的锁当然会影响性能。

然后,针对题主的问题,说说我的看法:

  1. volatile是用于解决缓存一致性问题,因为volatile实际上只是保证了对CPU缓存的操作立即flush到内存,此时的flush依然是以缓存行为单位的,也即你对某缓存行中的单个变量的volatile实际上是应用到了整个缓存行的所有变量,进而会有不同变量的不必要的操作同步,影响性能,此时便需要解决这个问题。
  2. 缓存行填充就是为了解决伪共享产生的性能问题的,实现方式是使用无用变量填充掉特定行多余部分。所以具体实现的时候,我认为一般情况下,为了性能上的考虑,对volatile变量最好还是应用缓存行填充,而高并发写情况下那是毋庸置疑必须进行填充,否则伪共享问题就真的成了他们所说的“性能杀手”了。
  3. 而不在volatile的情况下,缓存行依然存在,只不过若没有涉及到并发写,就不会有伪共享问题,但如果涉及到并发写,又会用volatile来解决缓存一致性问题。所以从这个角度来说,volatile也算是与缓存行填充一一对应。但有一点还是有必要分清楚,缓存行其实并不与volatile直接关联,而是与同一缓存行中不同变量的并发写直接关联,volatile是解决并发写,缓存行填充是解决并发写时flush缓存行产生的伪共享性能问题。

最后总结一下题主两个问题的答案:

  1. 缓存一致性是一个需要解决的问题,volatile缓存行填充是解决两个不同但有一定关联关系的问题的方式,如果没有并发写,也就没有缓存一致性问题,也就不需要volatile和缓存行填充了
  2. 缓存行填充是为了解决伪共享问题,理论上来说,所有并发写入同一缓存行的不同变量的操作都会产生伪共享问题,高并发下volatile变量频繁写肯定需要进行缓存行填充。至于disruptor框架,不巧我还不是很了解,但如果你能手动进行缓存行填充的话,也不是必须要用吧?
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏