我正在尝试理解Java内存模型和线程。据我所知,每个线程都有一个“主”内存的本地副本。因此,如果一个线程试图更改某个对象的int变量,它会缓存int变量,如果它更改了该变量,其他线程可能看不到更改。
但是如果线程缓存的是某个对象而不是int呢?在这种情况下,哪些线程会缓存它?如果线程缓存了对对象的引用,那么对该对象状态的任何更改对其他线程都是不可见的吗?为什么?
发布于 2013-12-13 05:26:04
CPU有不同级别的缓存L1、L2、L3。每个CPU (以及/may CPU Core)都有自己的缓存。此高速缓存存储最小的主内存(RAM)集以提高性能。
_______________ ______________
| CPU 1 | | CPU 2 |
| _________ | | _________ |
| | Level 1 | | | | Level 1 | |
| | Cache | | | | Cache | |
| | | | | | | |
| |_________| | | |_________| |
|_______________| |______________|
| | | |
| | | |
_|_|______________|_|__
| |
| MAIN MEMORY |
|_______________________|
Time Command CPU 1 (Cache) CPU 2 (Cache) Main Memory
------- ---------- ---------------- -------------- -------------
1 --- --- --- x = 10
2 Read x (on cpu1) x = 10 --- x = 10
3 Write x <--20 (on cpu1) x = 20 --- x = 10
4 Read x (on cpu2) x = 20 x = 10 x = 10
5 put cache to Main mem x = 20 x = 10 x = 20例如,在执行顺序上,x值在CPU2上是错误的。X值已被CPU1更改。如果x变量被定义为易失性,则所有写操作立即反映到主存储器。
发布于 2013-12-13 04:02:50
=============================================================
由于许多原因,下面的答案是错误的。请不要使用任何其他目的,而不是有一个爆炸。现代CPU上的缓存始终是一致的。
=============================================================
线程没有内存的本地副本。线程读/写的存储器的一部分可以来自高速缓存,而不是主存储器。缓存不需要彼此同步,也不需要与主内存同步。所以这就是你可以观察到的不一致之处。
,因此,如果一个线程试图更改一个int变量,例如某个对象,它会缓存该int变量,而如果它更改了该变量,其他线程可能看不到更改。
这是正确的。Java内存模型在先于规则发生中定义,例如,在字段x的易失性写入和字段x的易失性读取之间存在先于发生的规则。因此,当写入完成时,后续读取将看到写入的值。
如果没有这样的先行关系,所有的赌注都会失效(另外,当没有先行规则时,指令重新排序可能会使情况变得复杂)。
如果线程缓存了对对象的引用,对对象状态的任何更改对其他线程也是不可见的吗?为什么?
它可能是可见的..。它也可能是不可见的。如果没有先于规则发生,所有的赌注都是。原因是,否则许多优化,如硬件技巧,以加快速度,或编译器技巧将是不允许的。当然,总是保持内存与缓存同步会降低性能。
===========================================================
发布于 2013-12-13 05:15:16
CPU有多个缓存。正是这些硬件缓存可能具有不一致的数据副本。它们可能不一致的原因是,保持所有内容的一致性会使您的代码减慢10倍,并破坏您从拥有多个线程中获得的任何好处。要获得良好的性能,您需要有选择地保持一致。Java内存模型描述了何时确保数据的一致性,但在最简单的情况下,它不会。
注意:这不仅仅是CPU的问题。不需要在线程之间保持一致的字段可以在代码中内联。这可能意味着,如果一个线程更改了该值,另一个线程可能永远不会看到这个更改,因为它已经被写入代码中。
https://stackoverflow.com/questions/20552945
复制相似问题