- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在使用具有 ConcurrentHashMap 形式的对象存储的现有代码。映射中存储了可变对象,供多个线程使用。按照设计,没有两个线程会尝试同时修改一个对象。我担心的是线程之间修改的可见性。
目前,对象的代码在“setter”(由对象本身保护)上同步。 “ setter/getter ”没有同步,成员也不是易变的。对我来说,这意味着无法保证可见性。然而,当一个对象被修改时,它被重新放置回到 map 中(再次调用put()
方法,相同的键)。这是否意味着当另一个线程将对象从 map 中拉出时,它会看到修改?
我在 stackoverflow 上研究过这个,在 JCIP ,并在 java.util.concurrent 的包描述中。我想我基本上把自己弄糊涂了……但导致我问这个问题的最后一根稻草来自包裹描述,它指出:
Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.
关于我的问题,“ Action ”是否包括在 re-put() 之前对映射中存储的对象的修改?如果所有这些确实导致跨线程的可见性,这是一种有效的方法吗?我对线程比较陌生,非常感谢您的意见。
编辑:
谢谢大家的回复!这是我在 StackOverflow 上的第一个问题,它对我很有帮助。
我必须选择 ptomli的回答,因为我认为它最清楚地解决了我的困惑。也就是说,在这种情况下建立“先于发生”关系并不一定会影响修改的可见性。关于我在文中描述的实际问题,我的“标题问题”构造不当。 ptomli现在的答案与我在 JCIP 中读到的内容一致:“为确保所有线程都能看到共享可变变量的最新值,读写线程必须在公共(public)锁上同步”(第 37 页)。将对象重新放回映射中不会为插入对象的成员的修改提供此公共(public)锁。
我很欣赏所有关于更改的提示(不可变对象(immutable对象)等),并且我全心全意地同意。但是对于这种情况,正如我所提到的,由于仔细的线程处理,没有并发修改。一个线程修改一个对象,另一个线程稍后读取该对象(CHM 是对象传送器)。在我提供的情况下,我认为 CHM 不足以确保稍后执行的线程将看到第一个线程的修改。不过,我认为你们中的许多人正确回答了标题问题。
最佳答案
您在每次写入对象后调用 concurrHashMap.put
。但是,您没有指定在每次读取之前还调用 concurrHashMap.get
。这是必要的。
所有形式的同步都是如此:您需要在两个线程中都有一些“检查点”。只同步一个线程是没有用的。
我没有检查 ConcurrentHashMap 的源代码以确保 put
和 get
触发 happens-before,但它们应该是合乎逻辑的。
但是,即使您同时使用了 put
和 get
,您的方法仍然存在问题。当您修改一个对象并且它在 put
之前被另一个线程使用(处于不一致状态)时,就会出现问题。这是一个微妙的问题,因为您可能认为旧值会被读取,因为它还没有被 put
并且它不会导致问题。问题是当你不同步时,你不能保证得到一个一致的旧对象,而是行为是未定义的。 JVM 可以随时更新其他线程中对象的任何部分。只有在使用某些显式同步时,您才能确保以一致的方式跨线程更新值。
你可以做什么:
(1) 在代码的任何地方同步对你的对象的所有访问(getters 和setters)。小心 setter :确保您不能将对象设置为不一致的状态。例如,当设置名字和姓氏时,有两个同步的 setter 是不够的:您必须同时为两个操作获取对象锁。
或者
(2) 当您在 map 中放置
一个对象时,放置一个深拷贝而不是对象本身。这样其他线程将永远不会读取处于不一致状态的对象。
编辑:
我刚注意到
Currently the objects' code has synchronization on the "setters" (guarded by the object itself). There is no synchronization on the "getters" nor are the members volatile.
这样不好。正如我上面所说,只在一个线程上同步根本就不是同步。您可能会在所有编写器线程上进行同步,但谁在乎呢,因为读者不会获得正确的值。
关于java - 将对象重新放入 ConcurrentHashMap 是否会导致 "happens-before"内存关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7809131/
我最初构造了一系列嵌套的 ConcurrentHashMaps private final ConcurrentHashMap allInOne = new ConcurrentHashMap
我正在尝试使用 ConcurrentHashMap 初始化 ConcurrentHashMap private final ConcurrentHashMap > myMulitiConcurrent
为了提高工作效率,我尝试将数据保存在一个动态容器中。 我在 class 中初始化它与 private final ConcurrentHashMap allInOne = new Concur
我正在创建基于 Socket 的服务器-客户端预订服务,并且遇到有关将由多个线程访问的类的问题,是否需要扩展 ConcurrentHashMap 或创建变量 ConcurrentHashMap 是否足
从 Javadoc 我知道 ConcurrentHashMap.replace 是原子的,但是 ConcurrentHashMap.put 呢?我看到它们在源代码中的实现方式不同,但我无法弄清楚它们的
是 ConcurrentHashMap.get() 保证看到以前的ConcurrentHashMap.put()通过不同的线程?我的期望是,阅读 JavaDocs 似乎表明了这一点,但我 99% 确信
使用 ConcurrentHashMap,我发现 computeIfAbsent 比 putIfAbsent 慢两倍。这里是简单的测试: import java.util.ArrayList; imp
我有一个以下格式的 ConcurrentHashMap: ConcurrentHashMap> 现在在此 map 中,我想删除数组列表中的特定值。任何人都可以指导这一点。 编辑1:我有一张 map >
为什么 ConcurrentHashMap.Segment 和 ConcurrentHashMap.HashEntry 类是静态的?为什么要这样设计? 最佳答案 基本上所有不需要使用其封闭类属性的内部
在 ConcurrentHashMap 中通过键递增并发计数器时,使用常规 Int 作为值是否安全,还是我们必须使用 AtomicInteger?例如考虑以下两个实现 ConcurrentHashMa
我对java中的并发数据结构有疑问,特别是: 1) ConcurrentHashMap 2) HashMap 3) ConcurrentHashMap 如果我理解正确的话: 1) 读/写是线程安全的,
我正在尝试查看实际的 Java 文档,描述传递给 ConcurrentHashMap.computeIfAbsent 和 ConcurrentHashMap.computeIfPresent< 时可以
我有一个名为 SerializableL 的接口(interface)由 3 个不同的类实现: 产品 横幅 标签 我开始重构,想用多个方法调用替换多个段落。 public void load(Conc
一 JDK 中的 ConcurrentHashMap 在 JDK 8以前,HashMap 是基于数组 + 链表来实现的。整体上看,HashMap 是一个数组,但每个数组元素又是一张链表。 当向 Has
我想知道当我们在调整大小时尝试读取 ConcurrentHashMap 时可能发生的情况。 我知道在读取期间,第一次尝试总是不同步的。在第二次尝试中,它将尝试获取锁并重试。 但是,如果它在调整大小时发
在一个应用程序中,1 个线程负责不断更新映射,主线程定期读取映射,使用 ConcurrentHashmap 是否足够?或者我应该明确地锁定同步块(synchronized block)中的操作吗?任何
介绍 ConcurrentHashMap 技术是为了解决问题而生的,ConcurrentHashMap 解决了多个线程同时操作一个 HashMap 时,可能出现的内部问题。当多个线程同时操作一
我有一个由多个线程访问的键值映射: private final ConcurrentMap key_vval_map = new ConcurrentHashMap(); 我的自定义 get() 和
谁能告诉我这段代码出了什么问题?我要拔头发了! 如果我使用 HashMap 而不是 ConcurrentHashMap 则没有任何问题。代码使用JDK 5.0编译 public class MapTe
来自 ConcurrentHashMap 的源码 /** 171 * Number of unsynchronized retries in size and containsVal
我是一名优秀的程序员,十分优秀!