[英]Threadsafe way of exposing keySet()
这必须是一个相当常见的情况,我有一个地图,并希望线程安全地公开其密钥集:
public MyClass {
Map<String,String> map = // ...
public final Set<String> keys() {
// returns key set
}
}
现在,如果我的“地图”不是线程安全的,那么这是不安全的:
public final Set<String> keys() {
return map.keySet();
}
而且都不是:
public final Set<String> keys() {
return Collections.unmodifiableSet(map.keySet());
}
所以我需要创建一个副本,例如:
public final Set<String> keys() {
return new HashSet(map.keySet());
}
但是,这似乎并不安全,因为该构造函数遍历参数的元素并添加()它们。 因此,在进行此复制时,可能会发生ConcurrentModificationException。
那么:
public final Set<String> keys() {
synchronized(map) {
return new HashSet(map.keySet());
}
}
似乎是解决方案。 这看起来不错吗?
除非您计划在地图上同步使用它,否则该解决方案并不是特别有用。 在它上进行同步并不会阻止其他人同时在其上调用方法。 它只能阻止它们同步它。
如果你知道你需要并发put和删除而有人可能正在迭代,那么最好的解决方案似乎只是首先使用ConcurrentHashMap
。 如果类提供的并发行为不是您所需要的,那么您可能只需要使用完全同步的Map。
好问题。 我会使用Google Guava库。 更具体地说, com.google.common.collect.ImmutableSet.copyOf(Collection<? extends E>)
方法。 在文档中,据说这种方法是线程安全的。
如果您对线程安全迭代器感兴趣,并且在迭代过程中具有元素的精确快照,那么请转到下面。
public class ThreadSafeIteratorConcurrentMap
{
private ConcurrentMap<String, String> itrSafeMap = null;
public ThreadSafeIteratorConcurrentCollection() {
itrSafeMap = new ConcurrentHashMap<String, String>
}
public void synchronized put(psConference conference, String p_key)
{
itrSafeMap.putIfAbsent(p_key, conference);
}
public psConference getConference(String p_key)
{
return (itrSafeMap.get(p_key));
}
public void synchronized remove(String p_key)
{
itrSafeMap.remove(p_key);
}
public boolean containsKey(String p_key)
{
return itrSafeMap.containsKey(p_key);
}
// Get the size of the itrSafeMap.
public int size()
{
return itrSafeMap.size();
}
public Iterator<String> valueIterator()
{
return (itrSafeMap.values().iterator());
}
public Iterator<String> keyIterator()
{
return (itrSafeMap.keySet().iterator());
}
}
然后你想要线程安全的迭代器与元素的精确快照; 然后在同步块中使用它,如下所示。
synchronized(threadSafeIteratorConcurrentMapObject) {
Iterator<String> keyItr = threadSafeIteratorConcurrentMapObject.keyIterator();
while(keyItr.hasNext()){
// Do whatever
}
}
如果您不介意在迭代时修改集合; 只关注迭代器创建时元素的快照; 然后没有同步块你可以使用keyItr。 哪个已经是线程安全的; 它不会通过ConcurrentModificationException。
另一种选择是使用ConcurrentHashMap。 它的keySet()是线程安全的,因此可能不需要同步或复制。
您可以使用Collections.UnmodifiableMap
创建临时Map,然后迭代键集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.