Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java哈希映射线程可见性_Java_Multithreading_Concurrency - Fatal编程技术网

java哈希映射线程可见性

java哈希映射线程可见性,java,multithreading,concurrency,Java,Multithreading,Concurrency,我在初始化时完全加载java HashMap,但在初始化之后,多个线程将从HashMap读取数据。我希望避免任何类型的同步,因为映射本质上是只读的,从不更改。但是我可以保证所有的键和值对所有线程都是可见的吗?如果映射的内容从未更改,那么您就不会有问题。只有当变量的内容发生变化时,内存模型可见性问题才会出现 您可能希望同步映射的初始化,以确保在映射完全初始化之前没有线程访问它,并确保加载到映射中的值都是可见的 编辑:最初我完全忽略了地图如何初始化的问题。在阅读(再次)之后,似乎地图真的需要是最终的

我在初始化时完全加载java HashMap,但在初始化之后,多个线程将从HashMap读取数据。我希望避免任何类型的同步,因为映射本质上是只读的,从不更改。但是我可以保证所有的键和值对所有线程都是可见的吗?

如果映射的内容从未更改,那么您就不会有问题。只有当变量的内容发生变化时,内存模型可见性问题才会出现

您可能希望同步映射的初始化,以确保在映射完全初始化之前没有线程访问它,并确保加载到映射中的值都是可见的

编辑:最初我完全忽略了地图如何初始化的问题。在阅读(再次)之后,似乎地图真的需要是最终的,以便初始化数据变得可见:

查看字段正确构造的值的能力很好,但是如果字段本身是引用,那么您还希望代码能够查看它所指向的对象(或数组)的最新值。如果您的字段是最终字段,这也是有保证的。因此,您可以拥有指向数组的最终指针,而不必担心其他线程看到数组引用的正确值,但数组内容的值不正确。同样,这里的“正确”是指“截至对象构造函数结束时的最新值”,而不是“可用的最新值”


Java规范中给出了一个强制“在之前发生”关系的条件列表,我应该在这里引用它们(或者如果其他人在回答中这样做,我会投赞成票)。静态变量和Holder习惯用法当然是一种方法。这个问题相当广泛,因为它没有指定映射是如何初始化的,如果您发布一个描述您打算如何进行初始化的问题,您可能会得到一个更直接有用的答案

使用Guava将是最好的解决方案。

只要在读取开始之前完成初始化,就没有理由让每个线程都看不到HashMap的所有内容。

我想安全的方法是将其声明为final并在构造函数中初始化:

如果所有线程都只需阅读它。为了确保不可变,我将在初始化后将映射转换为不可修改的映射:

map = Collections.unmodifiableMap(map);

如果线程调用一个操作来修改映射,则会抛出一个
不支持操作异常

如果将HashMap声明为final,并且预先初始化本地HashMap,则将全局HashMap与本地,构造函数初始化后,HashMap的内容被计算为可访问

必须正确使用Final字段来 提供不变性的保证。 一个对象被认为是 当其 建造师完成。一根线 只能看到对对象的引用 在那个物体被完全摧毁之后 初始化后,保证可以看到 已正确初始化该文件的值 对象的最终字段


这是正确的答案。

我打赌你的地图是一个静态字段,那么是的,不同步阅读它是安全的

class SomeClass
    static Map map = init();
这是因为JVM为类初始化执行隐式双重检查锁定

基本上,你想要一个单身汉。有几种工艺,使用静电场就是其中之一。我打赌你的地图是一个“全局”的东西,所以它自然是一个静态字段,因此线程安全


有些情况下,延迟初始化的数据结构不是全局的,因此我们需要其他单例实现方案,包括即时同步、易失性引用或通过中间最终引用。查看wikipedia上的双重检查锁定

Java总是让我感到惊讶,但为什么要对任何线程隐藏任何密钥呢?除非在映射的init之前触发线程?@Santiago,它不是java,而是硬件:)。由于无序写入和CPU缓存,某些写入可能无法到达另一个CPU,您可能会使写入过时;另一方面,John V说,最简单、最直接的方法是使用额外的方法
map createMap(){}
并在c-tor中调用最终字段映射。即使该字段不是最终字段,也很有可能通过易失性变量(队列/交换器)或语义之前发生的任何事件使该对象对其他线程可用/可见,因此最终这无关紧要。如果它是一个
静态
字段,您就可以了。请看我的答案。+1这提供了一个可靠的保证,线程不能在该部分中断代码。除非同步或volatile特别指定,否则我的理解是JMM可以使用寄存器或cpu特定缓存,而不会刷新到主内存。我不相信java HashMap使用volatile或同步。那么,如何确保这些值对其他线程是可见的呢?这可能不是真的,根据内存模型,我认为hashmap的最终put及其初始读取没有garuntee(发生在排序之前)。有什么理由不这么认为吗?@richs:这就是为什么我补充说,你想同步初始化,你想确保你的初始值是可见的,并且同步会强制执行。不过,在初始化之后,只要不对映射进行进一步的更改,缓存和内存就没有理由不同。但是,即使同步,线程也不能看到部分初始化的HashMap吗?假设线程A开始初始化HashMap,在时间1创建映射,在时间2-10添加HashMap。在时间3线程B进入时,see的映射被初始化,因此时间3之后的所有add都不可见。Pugh在我链接的记忆模型中详细介绍了类似的内容。当我说“w”