Java内存模型(JSR-133)是否意味着进入监视器会刷新CPU数据缓存?

Dur*_*dal 17 java multithreading synchronization memory-model cpu-cache

有一些东西让我对Java内存模型感到困扰(如果我甚至正确理解了所有内容).如果有两个线程A和B,则无法保证B将看到A写入的值,除非A和B在同一监视器上同步.

对于保证线程之间的高速缓存一致性的任何系统体系结构,没有问题.但是,如果架构不支持硬件中的缓存一致性,这实质上意味着每当线程进入监视器时,之前所做的所有内存更改都必须提交到主内存,并且缓存必须无效.它需要是整个数据缓存,而不仅仅是几行,因为监视器没有信息,它在内存中保存哪些变量.但这肯定会影响任何需要频繁同步的应用程序的性能(特别是像短时间运行的作业队列这样的事情).那么Java可以在没有硬件缓存一致性的架构上合理地工作吗?如果没有,为什么内存模型不能提供更强的可见性保证?如果语言需要监视器保护的信息,那会不会更有效率?

正如我所看到的,内存模型给我们带来了两个世界中最糟糕的,绝对需要同步,即使硬件中保证了高速缓存一致性,另一方面,非相干体系结构上的性能不佳(完全高速缓存刷新).因此,它不应该更严格(需要信息由监视器保护)或更多地丢失和限制缓存一致的架构的潜在平台?

就像现在一样,它对我来说没有多大意义.有人可以清楚为什么选择这种特定的记忆模型吗?


编辑:回想起来,我对严格和失败的使用是一个糟糕的选择.我对"保证较少"的情况使用"严格",而对相反则"丢失".为了避免混淆,最好用更强或更弱的保证来说话.

Buu*_*yen 6

绝对需要同步,即使硬件中保证了缓存一致性

是的,但是你只需要反对Java内存模型,而不是针对程序碰巧运行的特定硬件架构.此外,它不仅涉及硬件,编译器和JIT本身可能会重新排序导致可见性问题的指令.Java中的同步构造在所有可能的代码转换级别(例如编译器/ JIT/CPU /缓存)中始终如一地查看可见性和原子性.

另一方面,非相干架构上的性能不佳(完全缓存刷新)

也许我误解了s/t,但是由于架构不连贯,你必须同步关键部分.否则,由于重新排序,您将遇到各种竞争条件.我不明白为什么Java内存模型会让事情变得更糟.

不应该更严格(要求显示器监视的信息)

我认为不可能告诉CPU完全刷新缓存的任何特定部分.编译器可以做的最好的事情是发出内存防护,并让CPU决定缓存的哪些部分需要刷新 - 它比你想要的更粗粒度.即使可以进行更细粒度的控制,我认为这会使并发编程变得更加困难(已经很难了).

AFAIK,Java 5 MM(就像.NET CLR MM一样)比x86和IA64等常见架构的内存模型更"严格".因此,它使得它的推理相对简单.然而,它显然不应该提供更接近顺序一致性的s/t,因为这会严重损害性能,因为可以应用更少的编译器/ JIT/CPU /缓存优化.


Bla*_*ade 5

现有体系结构保证了缓存一致性,但它们并不保证顺序一致性 - 两者是不同的.自seq.不保证一致性,硬件允许一些重新排序,您需要关键部分来限制它们.关键部分确保一个线程写入的内容变得对另一个线程可见(即,它们阻止数据争用),并且它们还会阻止经典竞争条件(如果两个线程增加相同的变量,则需要为每个线程读取当前变量值和写入的新值是不可分割的).

而且,执行模型并不像您描述的那样昂贵.在大多数现有体系结构中,它们是缓存一致但不是顺序一致的,当您释放锁定时,必须清除对内存的挂起写入,当您获得一个时,您可能需要做一些事情以确保将来的读取不会读取过时的值 - 这主要意味着只是防止读取过早移动,因为缓存保持连贯; 但仍然不能移动读取.

最后,您似乎认为Java的内存模型(JMM)是特殊的,而基础现在是相当先进的,类似于Ada,POSIX锁(取决于标准的解释)和C/C++内存模型.您可能需要阅读JSR-133手册,该手册解释了如何在现有架构上实现JMM:http://g.oswego.edu/dl/jmm/cookbook.html.