[英]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.