繁体   English   中英

如何安全地同时修改Java HashMaps中的值?

[英]How to safely modify values in Java HashMaps concurrently?

我有一块Java代码,看起来像这样,我正在尝试并行化:

value = map.get(key);
if (value == null) {
    value = new Value();
    map.put(key,value);
}
value.update();

我想阻止其他任何线程使用该特定键访问映射,直到调用value.update()之后, 即使键不在键集中也是如此 应允许使用其他键进行访问。 我怎样才能做到这一点?

简短的答案是,没有同步整个块就没有安全的方法。 不过,您可以使用java.util.concurrent.ConcurrentHashMap有关更多详细信息 ,请参见本文。 基本思想是使用ConcurrentHashMap.putIfAbsent而不是普通put

您无法将更新并行化到HashMap,因为更新会触发基础数组的大小调整,包括重新计算所有键。

使用其他集合,例如java.util.concurrent.ConcurrentHashMap,它是一个“哈希表,支持检索的完全并发和可调整的预期并发更新。” 根据javadoc。

如果您需要关注线程问题,则不会使用HashMap。 利用Java 5并发包并查看ConcurrentHashMap。

您刚刚描述了Guava计算图的用例。 使用以下方法创建它:

Map<Key, Value> map = new MapMaker().makeComputingMap(new Function<Key, Value>() {
  public Value apply(Key key) {
    return new Value().update();
  }
));

并使用它:

Value v = map.get(key);

这样可以确保只有一个线程将调用update()而其他线程将阻塞并等待该方法完成。

您可能实际上并不希望您的值具有可变的更新方法,但这是另一种讨论。

private void synchronized functionname() {
    value = map.get(key);
    if (value == null) {
        value = new Value();
        map.put(key,value);
    }
    value.update();
}

您可以在此处了解有关同步方法的更多信息: 同步方法

您可能还想研究可能适合您目的的ConcurrentHashMap类。 您可以在JavaDoc上看到它。

查看并发HashMap 即使对于单线程应用程序,它也具有出色的性能。 它允许从各个线程并发修改Map,而无需阻止它们。

一种可能性是管理多个锁。 因此,您可以保留一个基于键的哈希码检索的锁数组。 这样可以为您提供更好的吞吐量,然后再同步整个方法。 您可以根据您认为将要访问代码的线程数来确定数组的大小。

private static final int NUM_LOCKS = 16;
Object [] lockArray = new Object[NUM_LOCKS];
...
// Load array with Objects or Reentrant Locks

...

Object keyLock = lockArray[key.hashcode % NUM_LOCKS];
synchronize(keyLock){
  value = map.get(key);
  if (value == null) {
    value = new Value();
    map.put(key,value);
  }
  value.update();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM