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