我有一块看起来像我正在尝试并行化的Java代码:
value = map.get(key);
if (value == null) {
value = new Value();
map.put(key,value);
}
value.update();
我想阻止任何其他线程使用该特定键访问地图,直到value.update()
被调用,即使密钥不在密钥集中。应允许使用其他密钥访问。我怎么能做到这一点?
答案 0 :(得分:5)
简短的回答是,如果不同步整个块,就没有安全的方法。您可以使用java.util.concurrent.ConcurrentHashMap,请参阅this article for more details.基本提示是使用ConcurrentHashMap.putIfAbsent
代替普通put
。
答案 1 :(得分:2)
您无法并行化对HashMap的更新,因为更新可以触发基础数组的大小调整,包括重新计算所有键。
使用其他集合,例如java.util.concurrent.ConcurrentHashMap,它是“支持检索的完全并发和可更新的预期并发性的哈希表”。根据javadoc。
答案 2 :(得分:1)
如果您需要关注线程问题,我不会使用HashMap。使用Java 5并发包并查看ConcurrentHashMap。
答案 3 :(得分:1)
您刚刚描述了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()
,其他线程将阻塞并等待该方法完成。
您可能实际上并不希望您的值具有可变更新方法,但这是另一个讨论。
答案 4 :(得分:0)
private void synchronized functionname() {
value = map.get(key);
if (value == null) {
value = new Value();
map.put(key,value);
}
value.update();
}
您可以在此处详细了解同步方法:Synchronized Methods
您可能还想调查ConcurrentHashMap
类,这可能适合您的目的。您可以在JavaDoc上看到它。
答案 5 :(得分:0)
查看Concurrent HashMap。即使对于单线程应用程序,它也具有出色的性能。它允许从各种线程并发地修改Map,而无需阻止它们。
答案 6 :(得分:0)
一种可能性是管理多个锁。因此,您可以保留基于密钥哈希码检索的锁数组。这应该给你更好的吞吐量,然后同步整个方法。您可以根据您认为将访问代码的线程数来调整数组的大小。
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();
}