【问题标题】:Concurrent read access on map structure without lock无锁地图结构的并发读取访问
【发布时间】:2017-04-30 00:30:05
【问题描述】:

我有一个哈希图:

LinkedHashMap<Long, List<IOperation>> operations.

这是由多个线程写入的。我在它周围加了一把锁。

synchronized (lock){...}

确保在给定时刻只有 1 个线程对其进行写入。

尽管如此,在某些情况下我需要对其进行一些长读请求。

为此我复制了地图:

temp.putAll(operations);

= new LinkedHashMap<>(operations)

有没有办法在以下前提下制作这样的副本:

  • 复制时无需锁定地图。
  • 地图及其副本的成员没有按值调用。

已经谢谢了

一些额外的细节。

我经常对其执行一些长读操作,性能至关重要。

【问题讨论】:

  • 基本上,不,您必须使用 lock 进行任何操作,尤其是您上面列出的那些操作。任何其他风险ConcurrentModificationException 或更糟。

标签: java multithreading hashmap linkedhashmap


【解决方案1】:

在初始化 LinkedHashMap&lt;Long, List&lt;IOperation&gt;&gt; 时将其包装在 Collections#synchronizedMap 中很可能对您来说更容易,这样地图上的每个原子操作都会同步,而不必自己进行。

如果您坚持复制Map 而不必锁定它,我会在开始阅读时使用同步的Map 创建另一个LinkedHashMap

Map<Long, List<IOperation>> copy = new LinkedHashMap<>(synchronizedMap);

您还可以通过使用 Map 作为锁将“长读取请求”简单地包装在同步块中来消除对 Map 副本的需要。

【讨论】:

  • 但是synchronizedMap是按插入顺序排列的吗?
  • 而且 synchronizedMap 不也为正常情况下的操作带来开销吗?
  • 只要您使用的MapLinkedHashMap,那么Map 将按插入排序。同步任何东西都会产生开销,但 JVM 可以通过根据使用情况优化锁来解决这个问题。
  • 如果我复制地图,值仍然连接? (引用保持不变?)
  • 这就是为什么我不建议复制地图的原因,因为每个引用都必须被深度复制(你必须实现它)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-21
  • 2014-01-13
  • 2016-03-08
  • 2016-10-13
相关资源
最近更新 更多