为什么共享变量缓存在CPU缓存中?

时间:2017-12-25 03:17:01

标签: java multithreading visibility shared-variable

我正在尝试理解Java内存模型,但未能对CPU缓存有所了解。

据我所知,在JVM中,我们有以下位置来存储本地和共享变量:

local variables -- on thread stack

shared variables -- in memory, but every CPU cache has a copy of it

所以我的问题是:为什么在堆栈中存储局部变量,并在CPU缓存中存储(缓存)共享变量?为什么不相反(假设CPU缓存太昂贵而无法存储),我们在CPU缓存中缓存局部变量并只从内存中获取共享变量?这是Java语言设计还是计算机体系结构的一部分?

此外:就像“CPU缓存”一样简单,如果多个CPU共享一个缓存怎么办?在具有多级缓存的系统中,哪个级别的缓存将共享变量的副本存储在?此外,如果在同一CPU内核中运行的线程超过1个,这是否意味着它们共享同一组缓存的共享变量,因此即使未定义共享变量volatile,也可以访问在同一个CPU上运行的其他线程是否仍可立即看到变量?

1 个答案:

答案 0 :(得分:1)

"本地"和#34;分享"变量在代码的上下文之外是没有意义的。他们不会影响州的缓存状态。根据你的国家存储地点来思考或推理它甚至都没有用; JMM存在的全部原因是这样的细节(从架构到架构不同)不会暴露给程序员。依靠低级硬件细节,您会询问有关JMM的错误问题。它对你的应用程序没有用,它使它变得脆弱,更容易破解,更难以推理,并且不太便携。

这就是说,一般来说,您应该假设任何程序状态(如果不是所有状态)都有资格被缓存。事实上,缓存的内容实际上并不重要,只是任何东西都可以,无论是原始类型还是引用类型,甚至是由多个字段封装的状态变量。无论线程运行的指令是什么(这些指令也因架构而异 - 请注意!),这些指令默认返回CPU以确定与缓存相关的内容和不缓存的内容;程序员不可能自己这样做(尽管 可能影响可以缓存状态变量,看看false sharing是什么)。

同样,我们还可以对x86做一些更多的概括,活跃的基元类型可能放在寄存器上,因为P / ALU能够以最快的速度使用它们。还有别的事。如果将原语移动到L1 / 2缓存(如果它们是核心本地的话),则它们可能很快就会被覆盖。如果CPU认为将来会有上下文切换,或者它不能,则可能会将状态变量放在共享L3上。硬件专家需要对此作出回应。

理想情况下,状态变量将存储在最近的高速缓存(寄存器,L1 / 2/3,然后是主存储器)中,并存储在处理器单元中。然而,由CPU来决定。 不可能来推断Java级别的缓存语义。即使启用了超线程(我不确定AMD等价物是什么),也不允许线程共享资源,即便如此,如果它们是,则回想一下可见性不是与共享状态变量相关的唯一问题;在处理器执行流水线操作的情况下,您仍然需要相应的指令来确保正确的排序(这甚至在您摆脱了CPU上的读/写缓冲之后),无论是hwsync还是适当的围栏或其他人。

同样,关于缓存属性的推理也没有用,因为JMM会为你处理,因为它是不确定的,其中/ when /什么是缓存的。此外,即使您确实知道何时/何时/有什么问题,仍然无法推断数据可见性;所有缓存都以相同的方式处理缓存数据,您需要依赖处理器更新ME(O)SI状态,指令排序,加载/存储缓冲,回写/通过等之间的缓存状态。而且你仍然无法解决操作系统和JVM级别可能出现的问题。同样,幸运的是,JDK允许您使用基本工具,例如volatilefinal和原子,这些工具在所有平台上一致地工作,并生成可预测且容易(呃)推理的代码。 / p>