是否需要使用同步块或锁来对外部ConcurrentHashmap进行外部同步?
答案 0 :(得分:2)
是和否。这取决于你在做什么。 ConcurrentHashMap对其所有方法(例如get和put)都是线程安全的。但是,对于非原子操作,不线程安全。以下是执行非原子操作的方法示例:
public class Foo {
Map<String, Object> map = new ConcurrentHashMap<String, Object>();
public Object getFoo(String bar) {
Object value = foo.get(bar);
if (value == null) {
value = new Object();
map.put(bar, foo);
}
return value;
}
}
这里的缺陷是调用getFoo
的两个线程可以接收不同的Object。请记住,在处理任何数据结构或类型时,即使像int
一样简单,非原子操作也总是需要外部同步。诸如AtomicInteger和ConcurrentHashMap之类的类有助于使一些常见的操作线程安全,但是不能防止检查然后设置操作,例如上面的getFoo
。
答案 1 :(得分:1)
如果需要锁定集合,则只需要外部同步。该集合不会暴露其内部锁。
ConcurrentMap已经putIfAbsent,但是如果对象的创建很昂贵,你可能不想使用它。
final ConcurrentMap<Key, Value> map =
public Value get(Key key) {
// allow concurrent read
return map.get(key);
}
public Value getOrCreate(Key key) {
// could put an extra check here to avoid synchronization.
synchronized(map) {
Value val = map.get(key);
if (val == null)
map.put(key, val = new ExpensiveValue(key));
return val;
}
}
答案 2 :(得分:0)
否:无需外部同步。
java.util.concurrent
类上的所有方法都是线程安全的。
答案 3 :(得分:0)
据我所知,所有需要的锁定都是在这个类中完成的,所以如果你没有做某些特定的事情并且需要它像这样起作用,你不需要太担心它。
在http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/ConcurrentHashMap.html上说:
但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且没有任何支持以阻止所有访问的方式锁定整个表。
检索操作(包括get)一般不会阻塞,因此可能与更新操作重叠(包括put和remove)。检索反映了最近完成的更新操作的结果。
因此,如果这不代表您的特定应用程序中的任何问题,您不必担心它。