我知道Java中易失性变量的目的是对此类变量的写入对其他线程立即可见。我还知道同步块的作用之一是将线程局部内存刷新到全局内存。
我从未完全理解在这种情况下对“线程本地”内存的引用。我知道仅存在于堆栈上的数据是线程本地的,但是当谈论堆上的对象时,我的理解变得模糊。
我希望得到关于以下几点的评论:
当在具有多个处理器的机器上执行时,刷新线程本地内存是否只是指将 CPU 缓存刷新到 RAM 中?
当在单处理器机器上执行时,这有什么意义吗?
如果堆有可能在两个不同的内存位置(每个由不同的线程访问)具有相同的变量,那么在什么情况下会出现这种情况?这对垃圾收集有什么影响?虚拟机做这种事情有多积极?
-
(编辑:添加问题4)退出同步块时会刷新哪些数据?它是线程本地拥有的一切吗?是否仅在同步块内进行写入?
Object x = goGetXFromHeap(); // x.f is 1 here
Object y = goGetYFromHeap(); // y.f is 11 here
Object z = goGetZFromHead(); // z.f is 111 here
y.f = 12;
synchronized(x)
{
x.f = 2;
z.f = 112;
}
// will only x be flushed on exit of the block?
// will the update to y get flushed?
// will the update to z get flushed?
总的来说,我认为我想了解线程本地是否意味着只能由一个CPU物理访问的内存,或者是否存在由虚拟机完成的逻辑线程本地堆分区?
任何演示文稿或文档的链接都会非常有帮助。我花了时间研究这个问题,虽然我发现了很多不错的文献,但我无法满足我对线程本地内存的不同情况和定义的好奇心。
非常感谢。
您所说的刷新被称为“内存屏障”。这意味着 CPU 确保它看到的 RAM 内容也可以从其他 CPU/内核看到。这意味着两件事:
JIT 编译器刷新 CPU 寄存器。通常,代码可能会在 CPU 寄存器中保存一些全局可见数据(例如实例字段内容)的副本。其他线程无法看到寄存器。这样一来,一半的工作synchronized
是为了确保不维护此类缓存。
The synchronized
实现还执行内存屏障,以确保当前核心对 RAM 的所有更改都传播到主 RAM(或者至少所有其他核心都知道该核心具有最新值 - 缓存一致性协议可能相当复杂) )。
第二项工作在单处理器系统上是微不足道的(我的意思是,具有单核的单个 CPU 的系统),但如今单处理器系统往往变得越来越少。
至于线程局部堆,理论上可以做到这一点,但通常不值得付出努力,因为没有任何东西告诉我们内存的哪些部分将被刷新synchronized
。这是共享内存线程模型的限制:all内存应该是共享的。第一次遇到的时候synchronized
,然后 JVM 应该将其所有“线程本地堆对象”刷新到主 RAM。
然而,Sun 最近的 JVM 可以执行“逃逸分析”,其中 JVM 成功地证明某些实例永远不会对其他线程可见。这是典型的,例如,StringBuilder
创建的实例javac
处理字符串的串联。如果实例从未作为参数传递给其他方法,那么它不会变得“全局可见”。这使得它适合线程本地堆分配,甚至在适当的情况下适合基于堆栈的分配。请注意,在这种情况下没有重复;该实例不是“同时在两个地方”。只是 JVM 可以将实例保存在私有位置,而不会产生内存屏障的成本。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)