Jac*_*ith 10 java memory multithreading model
我知道Java中volatile变量的目的是对其他线程立即可以看到对这些变量的写入.我也知道同步块的一个影响是将线程本地内存刷新到全局内存.
在这种情况下,我从未完全理解对"线程本地"内存的引用.我理解只存在于堆栈上的数据是线程本地的,但是当谈论堆上的对象时,我的理解变得模糊.
我希望能得到以下几点的评论:
在具有多个处理器的计算机上执行时,是否刷新线程本地内存只是将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?
Run Code Online (Sandbox Code Playgroud)总的来说,我想要了解线程局部是否意味着只有一个CPU可以物理访问的内存,或者VM是否存在逻辑线程局部堆分区?
任何演示文稿或文档的链接都会非常有用.我花时间研究这个,虽然我找到了很多不错的文献,但我还是无法满足我对线程局部记忆的不同情况和定义的好奇心.
非常感谢.
你所谈论的同花顺被称为"记忆障碍".这意味着CPU确保从RAM中看到的内容也可以从其他CPU /内核中查看.它意味着两件事:
JIT编译器刷新CPU寄存器.通常,代码可以保留CPU寄存器中的一些全局可见数据(例如,实例字段内容)的副本.从其他线程看不到寄存器.因此,一半的工作synchronized
是确保不维护这样的缓存.
该synchronized
实现还执行内存屏障,以确保从当前内核对RAM的所有更改都传播到主RAM(或者至少所有其他内核都知道此内核具有最新值 - 缓存一致性协议可能相当复杂).
第二项工作在单处理器系统上是微不足道的(我的意思是,具有单核CPU的系统具有单核)但是单处理器系统现在往往变得更加罕见.
至于线程局部堆,理论上可以做到这一点,但通常不值得努力,因为没有什么可以告诉内存的哪些部分需要刷新synchronized
.这是带共享内存的线程模型的限制:应该共享所有内存.在第一次遇到时synchronized
,JVM应该将其所有"线程局部堆对象"刷新到主RAM.
然而,Sun最近的JVM可以执行"逃逸分析",其中JVM成功地证明某些实例永远不会从其他线程中看到.例如,这是典型的StringBuilder
由javac
处理字符串连接而创建的实例.如果实例永远不作为参数传递给其他方法,那么它不会变为"全局可见".这使得它有资格进行线程局部堆分配,或者甚至在适当的情况下,用于基于堆栈的分配.请注意,在这种情况下,没有重复; 实例不在"两个地方同时".只有JVM才能将实例保存在私有的地方,而不会产生内存障碍.