【发布时间】:2018-03-26 02:01:12
【问题描述】:
简而言之来自java
在 Java 中,一个进程中的所有 Java 应用程序线程都有自己的 堆栈(和局部变量),但共享一个堆。这使它 在线程之间共享对象非常容易,因为只需要 将引用从一个线程传递到另一个线程。
这导致了 Java 的一般设计原则——对象是 默认可见。如果我有一个对象的引用,我可以复制 并将其交给另一个线程,没有任何限制。一个爪哇 引用本质上是指向内存中某个位置的类型化指针——并且 线程共享相同的地址空间,因此默认可见 是一个自然模型。
来自 Java 并发实践
可见性是微妙的,因为可能出错的事情是如此之多 违反直觉的。在单线程环境中,如果你写一个 变量的值,然后在没有干预的情况下读取该变量 写入,您可以期望得到相同的值。这似乎只是 自然的。一开始可能很难接受,但当阅读和 写入发生在不同的线程中,事实并非如此。在 一般的, 无法保证读取线程会及时看到另一个线程写入的值,甚至根本没有。在 为了确保跨线程内存写入的可见性,您必须 使用同步。
当一个线程在没有同步的情况下读取一个变量时,它可能会看到一个陈旧的值。
那么为什么 Java in a Nutshell 说对象对所有线程都是可见的,而 Java Concurrency in Practice 却说不能保证读取线程及时看到另一个线程写入的值?它们似乎不一致。
谢谢。
【问题讨论】:
-
Java In A Nutshell 是错误的,或者至少掩盖了一些微妙但非常重要的细节。他们应该说“所有对象在某些时候都是可见的,即使那样你也可能只看到其中的一些——除非你小心如何将它们交给另一个线程。”
-
所有对象都是可见的,但这并不意味着不同的线程会看到最新的值... ;) 阅读关于关键字 volatile 的移动
-
@alfasin 既然共享对象存储在线程共享的堆中,为什么有些线程可能看不到其他线程的最新值?
-
@Ben 因为线程可能缓存了这些对象的值
-
Nutshell 语句中的 Java 是正确的,这不是 Java 问题。它也适用于 C# 和 C++。有内存,可以访问(如果已提交)或不可以访问(如果保留)。并发这本书也是正确的,因为它谈到了数据竞争,当您并行读取和写入同一内存时会发生这种情况。
标签: java multithreading concurrency