线程缓存和 Java 内存模型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20552945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:45:49  来源:igfitidea点击:

Thread Caching and Java Memory model

javamemory-managementgarbage-collection

提问by user1409534

I'm trying to understand the Java memory model and threads. As fas has I understand, each thread has a local copy of the "main" memory. So if one thread tries to change an intvariable, for example, of some object, it caches the intvariable and if it changes it, other thread might not see the change. But what if threads cache some object instead of int? What threads cache it in this case? If a thread caches a reference to an object any change to the state of the object are not visible to other threads? Why?

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

Thank you in advance

先感谢您

回答by pveentjer

A thread doesn't have a local copy of memory. Part of the memory the thread reads/writes could be from a cache, instead of main memory. Caches do not need to be in sync with each other, or in sync with main memory. So this is where you can observe inconsistencies.

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

So if one thread tries to change a int variable for example of some object it caches the int variable and if it changes it other thread might not see the change.

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

That is correct. The Java Memory model is defined in happens before rules, e.g. there is a happens before rule between a volatile write of field x and a volatile read of field x. So when a write is done, a subsequent read will see the value written.

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

Without such a happens before relation, all bets are off (also instruction reordering can make life complicated when there is no happens before rule).

如果没有在关系之前发生这种情况,则所有赌注都将取消(如果规则之前没有发生,指令重新排序也会使事情变得复杂)。

If thread caches a reference to an object any change to the state of the object are also not visible to other threads? Why?

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

It could be visible.. it could also not be visible. Without a happens before rule, all bets are of. The reason why is that otherwise a lot of optimizations like hardware tricks to speed things up, or compiler tricks would not be allowed. And of course, always keeping memory in sync with the cache, would reduce performance.

它可以是可见的。它也可以是不可见的。如果没有发生在规则之前,所有的赌注都是。原因是否则将不允许进行许多优化,例如硬件技巧以加快速度或编译器技巧。当然,始终保持内存与缓存同步会降低性能。

回答by Rodmar Conde

"Before you can write decent multi-threaded code, however, you really need to study more on the complexities and subtleties of multi-threaded code.

“然而,在您编写体面的多线程代码之前,您确实需要更多地研究多线程代码的复杂性和微妙之处。

When it comes to threads, very little is guaranteed.

当涉及到线程时,几乎没有什么可以保证的。

Can you imagine the havoc that can occur when two different threads have access to a single instance of a class, an both threads invoke methods on that object... and those methods modify the state of the object? ... it's too scary to even visualize.", from Sun Certified Programmer for Java 6, chapter 9: Threads.

你能想象当两个不同的线程可以访问一个类的单个实例时会发生的严重破坏,两个线程都调用该对象上的方法......并且这些方法修改对象的状态吗?......甚至无法想象。”,来自 Sun Java 6 认证程序员,第 9 章:线程。

My friend,

我的朋友,

In Java, threads doesn't cache any object or variable, they just have a referenceto an instanceof an object. Talking about thread cache memoryis more like talking about operative systems threads... Java works in the same way in all OS, no matter how threads are managed internally, which differs very much depending on the different OS's.

在Java中,线程不会缓存任何对象或变量,他们只是有一个参考,以一个实例的的对象。谈论线程缓存更像是谈论操作系统线程...... Java 在所有操作系统中都以相同的方式工作,无论内部如何管理线程,这取决于不同的操作系统而有很大差异。

Look a this code:

看看这个代码:

AccountDanger r = new AccountDanger();
Thread one = new Thread(r):
Thread two = new Thread(r);

As you can see, in this case threads have access to the same instance: r. Then, you will have synchronization problems, for sure... it doesn't matters if we talk about native or object members, threads one and two will have access to all members of r(if they are accessiblevia scope or setters/getters) and they will read directly the values from rinstance. This is for sure even if you don't notice it, which is sometimes really hard.

如您所见,在这种情况下,线程可以访问同一个实例:r。然后,肯定会遇到同步问题......我们谈论本机或对象成员并不重要,线程一和二将可以访问r 的所有成员(如果它们可以通过作用域或 setter/getter 访问) ),它们将直接从r实例读取值。即使您没有注意到,这也是肯定的,这有时真的很难。

I recommend you reading about java scopesand java synchronization, if you want to code multi-threaded applications.

如果您想编写多线程应用程序,我建议您阅读有关java 作用域java 同步的内容

Regards,

问候,

回答by Peter Lawrey

CPUs have multiple caches. It is these hardware caches which might have inconsistent copies of the data. The reason they might be inconsistent is that keeping everything consistent can slow down your code by a factor of 10 and ruin any benefit you get from having multiple threads. To get decent performance you need to be selectively consistent. The Java Memory Model describes when it will ensure the data is consistent, but in the simplest case it doesn't.

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

Note: this is not just a CPU issue. A field which doesn't have to consistent between threads can be inlined in the code. This can mean that if one thread changes the value another thread might NEVER see this change as it has been burnt into the code.

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

回答by Erdin? Ta?k?n

CPU have different level caches L1, L2, L3. Every CPU (and also /may CPU Core) has own cache. This caches store minimal set of main memory (RAM) for performance.

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

For example, Above execution order, x value is wrong on CPU2. x value already changed by CPU1. If x variable is defined as volatile, all write operation reflect to main memory instantly.

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