理解CacheLine与写出更好的JAVA

今天查了很多资料,主要是想搞清楚写JAVA和CacheLine有什么关系以及我们如何针对CacheLine写出更好的JAVA程序。

CPU和内存

CPU是计算机的大脑,它负责运算,内存是数据,它为CPU提供数据。这里之所以忽略其他存储设备是为了简化模型。假设我们面对的是具有两个核心的CPU,那么我们的模型大概如下面的样子:

CPU计算核心不会直接和内存打交道,它会直接从缓存拿数据,如果缓存没拿到,专业点说即缓存未命中的时候才会去内存去拿,同时会更新缓存。这个过程CPU不会仅仅读取需要的某个字节或字的内容,而会按策略读取一块内容。典型的处理器策略是向前进的方向读取小于2048字节的数据。如上图所示,L1缓存(一级缓存)离CPU内核最近,容量也最小同时造价也最高,属于内核独立使用。L2缓存离得远些,容量比L1大写但是还是属于独立的内核使用。L3缓存离的最远,也是最慢的缓存,这层缓存为所有内核共享。

缓存行

上面一节我们介绍了CPU和内存之间的模型,本节介绍下缓存行。CPU从缓存中读取内容并不是一个字节或一个字读的,而是一行一行,也可以理解为一块一块读的。CPU是这样设计的,我们想想,相邻数据的相关性往往很大,这么设计可以提高缓存的命中率,也降低访问缓存的次数。上面提到的一行叫做缓存行。典型的大小是32-256字节,其中最常见的是64字节。这是缓存一致性的最小粒度,如果一行中有一个字节哪怕一个位的内容内修改并写回内存,那么其他内核的该缓存行将会被标志位无效。假设两个内核正在执行不同的线程,并且操作同一个缓存行,A线程修改了缓存行的第一个字节,B线程需要访问第二个字节,这个时候该缓存行其实已经被进行了一次和内存同步的操作,保证该段和内存中该行数据一致,然而这个过程B线程访问的这个字节和第一个线程访问的字节并没有关系。这个时候有同学有疑问了,那么如果两个内核的线程同时对该段进行操作,也就是没有谁先谁后的情况,会出现什么情况呢。其实这里涉及到另外一个概念,叫缓存一致性协议(Cache Coherency)。即我们已经有了一个保证:在任意时刻,任意级别的缓存段中的内容,等同于它对应的内存中的内容。

关于AtomicReference

AtomicReference是由JAVA5引入的,用于对一个对象引用进行原子操作,我们可以看到AtomicReference的实现是用CAS技术对引用进行指令级别的原子修改然后再利用volatile带来的内存屏障特性保证引用的修改对其他线程立即可见。这里提一点,由volatile修饰的变量在写之后会插入一个store屏障,在读之前插入一个load屏障。store屏障保证写操作被后面的线程立即可见。load屏障保证所有的读操作之前的写立即生效。然而AtomicReference并没有避免缓存行带来的缓存命中率问题。一个AtomicReference对象包括一个volatile的对象引用,即这个对象在32位操作系统中占4个字节,在64位操作系统中占8个字节。虽然多个线程对同一个AtomicReference对象操作没有并发问题,但是当多个线程对多个AtomicReference操作的时候就有可能有缓存命中率问题。借着上文中的模型我们假设两个AtomicReference变量A和B位于同一内存相邻区域,当在核心1执行的线程对A变量操作的时候CPU会将A变量读入核心1的缓存区域,同时捎带把B变量读入缓存区域,此时和A变量位于同一缓存行。核心2执行的另外一个线程同时对B进行操作,这个时候该缓存行已经失效,会发生一次读内存操作。

缓存行填充

Exchanger类是JAVA5提供的用于多线程之间交换数据的工具类,我们看看Exchanger的内部类Slot的实现:

?


1

2

3

4

 private static final class Slot extends AtomicReference<Object> {

        // Improve likelihood of isolation on <= 64 byte cache lines

        long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe;

    }

Slot只是简单的继承了AtomicReference类,并声明了15个long类型的变量。如果不懂CacheLine的话不会明白这段无用变量的意义,这里声明了15个long类型的变量,一个long类型为8个字节,加上上面的引用在64位操作系统环境下为128字节,32位操作系统环境下的124字节也没问题,因为两个Slot类型变量不可能位于同一缓存行,这也就解决了多核CPU环境下的缓存行失效问题。

时间: 2024-10-22 19:13:00

理解CacheLine与写出更好的JAVA的相关文章

如何写出更好的Java代码

Java是最流行的编程语言之一,但似乎并没有人喜欢使用它.好吧,实际上Java是一门还不错的编程语言,由于最近Java 8发布了,我决定来编辑一个如何能更好地使用Java的列表,这里面包括一些库,实践技巧以及工具. 这篇文章在GitHub上也有.你可以随时在上面贡献或者添加你自己的Java使用技巧或者最佳实践. 编码风格 结构体 builder模式 依赖注入 避免null值 不可变 避免过多的工具类 格式 文档 Stream 部署 框架 Maven 依赖收敛 持续集成 Maven仓储 配置管理

【整洁之道】如何写出更整洁的代码(上)

如何写出更整洁的代码 代码整洁之道不是银弹,不会立竿见影的带来收益. 没有任何犀利的武功招式,只有一些我个人异常推崇的代码整洁之道的内功心法.它不会直接有效的提高你写代码的能力与速度,但是对于程序员的整个职业生涯必然会带来意想不到的好处. 如果你还是一个在校学生,或者是刚工作没多久的"菜鸟",那么很有必要接触一些这方面的知识的.很显然,它会帮助你更快的适应企业级开发的要求. 1. 为什么需要代码更整洁? 在考虑代码整洁的时候,我们需要明确的一个前提是,这里不讨论代码的对错. 关于什么是

掌握解决问题的艺术,学会迭代开发,成为协作开发的专家,然后为写出更好的代码而担忧(转)

很多开发人员普遍犯有一个错误,认为他们的工作就是写代码.这不是一个开发人员要做的事情. 一个开发人员的工作是解决问题. 解决问题的一部分过程通常涉及到写代码,但是这部分工作是非常非常小的.开发有用的东西才花更多时间. 明白如何迭代开发,随着对问题有更好的理解,你才能给难题增加一些小功能,因为从头开发完美的产品是不可能的.不用写代码就能验证功能,因为很明显,写代码是相当昂贵的. 用于测试.评测和抛弃想法的系统也是极其重要的,因为要是没有它,整个开发组将耗费越来越多的精力,还有用来帮助他们执行得更有

[译] 如何在React中写出更优秀的代码

目录 我们先来看 Linting 利用组件模块性.复用性和组合性 propTypes 和 defaultProps 知道何时创建新组件 组件 vs 纯组件 vs 无状态函数组件 无状态函数组件 纯组件 使用 React 开发工具 使用内联条件语句 尽可能使用代码片段库 React 本质 - 学习 React 是如何工作的 快速回顾 在React中写出更好代码的9条建议:学习关于 Linting, propTypes, PureComponent 等. Rajat S · 2018 年 4 月 1

[label][翻译][JavaScript-Translation]七个步骤让你写出更好的JavaScript代码

7 steps to better JavaScript 原文:http://www.creativebloq.com/netmag/7-steps-better-javascript-51411781七个步骤让你写出更好的JavaScript代码 随着浏览器的性能提升,新的HTML5 APIS也在不断地被应用,JavaScript在web使用中不断增长.然而,一行糟糕的代码就有可能会影响到整个网站,产生糟糕的用户体验和造成潜在客户的流失. 开发者必须使用他所能使用的工具和技巧来提高代码的质量,

Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码

美国时间 09 月 25 日,Oralce 正式发布了 Java 11,这是据 Java 8 以后支持的首个长期版本. 为什么说是长期版本,看下面的官方发布的支持路线图表. Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码可以看出 Java 8 扩展支持到 2025 年,而 Java 11 扩展支持到 2026 年. 现在大部分都在用 Java 8,Java 9 和 10 目前很少有人在用,至少我没有发现有公司在生产环境应用的,那就是找死. 现在 Java 11 长期支持,也已

让我们一起写出更有效的CSharp代码吧,少年们!

周末空闲,选读了一下一本很不错的C#语言使用的书,特此记载下便于对项目代码进行重构和优化时查看. Standing On Shoulders of Giants,附上思维导图,其中标记的颜色越深表示在实际中的实际意义越大. 名称 内容和示例 提供API时尽量提供泛型接口 Public interface IComparable<T>{ int CompareTo(T other) } 泛型约束尽可能的严格并有效 Public delegate T FactoryFunc<T>();

Java 11正式发布,这几个逆天新特性教你写出更牛逼的代码

就在前段时间,Oracle 官方宣布 Java 11 (18.9 LTS) 正式发布,可在生产环境中使用! 这无疑对我们来说是一大好的消息.作为一名java开发者来说,虽然又要去学习和了解java11,但内心还是欣慰的.我想至少你和我一样的心情:Java在手,天下我有! 今天我们来看一下Java 11到底是什么.他有什么特别的.到底要不要升级到Java 11. Java 11有什么特别的 在Oracle官网中,进入下载页面,第一个可供下载的JDK版本已经提换成了Java SE 11 (LTS),

怎样写出更好的JavaScript代码

一.可维护性的代码 1.可读性:在函数和方法.大段代码.复杂算法和hack上加上帮助理解的注释.    2.变量的函数的命名:变量最好用名词,函数最好以动词开头.有较好的语义和逻辑性. 3.变量类型透明:以合适的命名方式来帮助记忆变量的类型 . a:初始化法. b:匈牙利标记法. c:在后面用注释说明. 4.松散耦合 松散耦合就是一部分的代码功能依赖于另外一部分.   a:html/javascript 解耦:html与js尽量分离,比如在html中添加事件处理,动态插入标签.解耦可以更快地知道