2013-12-12 76 views
14

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

谢谢您提前

回答

11

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

所以,如果一个线程试图改变一个int变量,例如某个对象,它会缓存int变量,如果它改变了它,其他线程可能看不到这个改变。

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

没有这样的关系之前发生,所有的赌注都关闭(也指令重新排序可以使生活变得复杂时,有没有规则之前发生)。

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

这可能是可见的。它也可以是不可见的。如果没有规则发生,所有投注都是。之所以会出现这种情况,是因为硬件技巧会加快速度,或者编译器的技巧不会被允许。当然,始终保持内存与缓存同步,会降低性能。

+1

请注意,“后续”与“写入后发生”不同。 'volatile'不提供任何*时间*保证,它只是关于*一致性*,从不观察写入顺序。 –

+0

@pveentjer你为什么这么说 - 它可能是可见的..它也可能不可见?只有引用缓存在线程本地堆栈中。所以这些更改应该在线程中可见。我错了吗 ?硬件/编译器技巧 - 请给出更清晰的图片。 – Kiran

-3

每个线程都没有本地内存副本。如果一个变量对多个线程可见(因为它的范围),每个线程都会看到相同的值。

然而,多线程程序需要非常小心共享变量(内存),因为它是很容易引入竞争条件,如果你不小心。

+2

我不这么认为,除此之外关键词'volatile'存在吗? – Chriss

+0

克里斯和史蒂夫,我想你们都不完全正确。没有线程本地高速缓存的内存(我相信早期版本的JVM中有线程高速缓存)。存在易失性的原因有很多: 1.防止CPU重新排序(在执行多核和多处理器的情况下) 2.防止可能中断对共享变量的并发访问的编译器和JIT优化。 它与竞赛条件无关。在某些情况下,挥发性可以帮助您避免它们,但这是一个更普遍的问题。 –

2

“之前,你可以写体面的多线程代码,但是,你真的需要更多的研究上的多线程代码的复杂性和微妙之处。

当涉及到线程,很少有保证。

你可以想象当两个不同的线程可以访问一个类的单个实例时会发生的破坏,两个线程都会调用该对象上的方法......并且这些方法会修改对象的状态?太可怕,甚至没有形象化。“,来自Sun Certified Programmer for Java 6的,第9章:线程。

我的朋友,

在Java中,线程不会缓存任何对象或变量,他们只是有一个参考对象实例。谈到线程缓存内存更像是在谈论个操作系统线程 ... Java的作品以同样的方式在所有的操作系​​统,线程无论多么内部管理,它不同于非常依赖于不同的操作系统。

看一个验证码:

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

正如你所看到的,在这种情况下,线程可以访问相同的实例:[R。然后,你将有同步问题,肯定...它没有问题,如果我们谈论本地或对象成员,线程一和二将有机会获得[R的所有成员(如果他们是通过范围或设置器/吸气剂可访问),并且它们将直接从ř实例中读取的值。这是肯定的,即使你没有注意到,这有时真的很难。

我建议你阅读java的范围Java同步,如果你想编写多线程应用程序。

Regards,

8

CPU有多个高速缓存。正是这些硬件缓存可能有不一致的数据副本。他们可能不一致的原因是保持所有内容的一致性会使你的代码减慢10倍,并破坏你从多线程中获得的好处。为了获得体面的表现,您需要有选择地保持一致。 Java内存模型描述了什么时候可以确保数据的一致性,但在最简单的情况下并不是这样。

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

17

CPU具有不同级别的高速缓存L1,L2,L3。每个CPU(也可能是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 

例如,上面的执行顺序,CPU2上的x值是错误的。 x值已由CPU1更改。 如果将x变量定义为易失性,则所有写入操作立即反映到主存储器中。