线程缓存和Java内存模型

use*_*534 24 java garbage-collection memory-management

我正在尝试理解Java内存模型和线程.据我所知,每个线程都有一个"主"内存的本地副本.因此,如果一个线程试图更改一个int变量(例如某个对象),它会缓存该int变量,如果它更改了变量,则其他线程可能看不到变化.但是如果线程缓存某些对象而不是int呢?在这种情况下,哪些线程会缓存它?如果一个线程缓存对象的引用,对对象状态的任何更改都不会被其他线程看到?为什么?

先感谢您

Erd*_*kın 29

CPU具有不同级别的高速缓存L1,L2,L3.每个CPU(以及/或CPU核心)都有自己的缓存.此高速缓存存储最小的主存储器(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
Run Code Online (Sandbox Code Playgroud)

例如,在执行顺序上,CPU2上的x值是错误的.x值已由CPU1更改.如果x变量定义为volatile,则所有写操作立即反映到主存.


pve*_*jer 14

线程没有内存的本地副本.线程读/写的部分内存可以来自缓存,而不是主内存.缓存不需要彼此同步,也不需要与主存储器同步.所以这是你可以观察到不一致的地方.

因此,如果一个线程试图更改一个int变量,例如某个对象,它会缓存int变量,如果它更改它,其他线程可能看不到更改.

那是正确的.Java存储器模型在规则之前定义,例如,在字段x的易失性写入和字段x的易失性读取之间的规则之前发生.因此,当写入完成后,后续读取将看到写入的值.

如果在关系之前没有这样的事情发生,所有的赌注都会被取消(当规则之前没有发生时,指令重新排序也会使生活变得复杂).

如果线程缓存对对象的引用,对对象状态的任何更改对其他线程也不可见?为什么?

它可能是可见的......它也可能不可见.所有投注都没有在规则之前发生.之所以如此,那么很多优化就像硬件技巧一样加快速度,或者不允许使用编译器技巧.当然,始终保持内存与缓存同步会降低性能.

  • 注意,"后续"与"写入后发生"不同.`volatile`不提供任何*及时性*保证,它只是*一致性*从不观察无序写入. (2认同)

Pet*_*rey 13

CPU有多个缓存.正是这些硬件缓存可能具有不一致的数据副本.它们可能不一致的原因是保持一致性会使代码速度降低10倍,并破坏从多线程中获得的任何好处.要获得不错的性能,您需要选择性地保持一致.Java内存模型描述了它何时确保数据是一致的,但在最简单的情况下却没有.

注意:这不仅仅是CPU问题.可以在代码中内联不必在线程之间保持一致的字段.这可能意味着如果一个线程更改了该值,则另一个线程可能永远不会看到此更改,因为它已被烧入代码中.

  • @ Andremoniy,JLS讨论了虚拟机的寄存器堆栈。这里没有讨论CPU的实际寄存器或缓存,因为这些是实现细节。 (2认同)