Java 什么';ConcurrentHashMap和Collections.synchronizedMap(映射)之间的区别是什么?
我有一个映射,它将由多个线程同时修改 Java API中似乎有三种不同的同步映射实现:Java 什么';ConcurrentHashMap和Collections.synchronizedMap(映射)之间的区别是什么?,java,dictionary,concurrency,Java,Dictionary,Concurrency,我有一个映射,它将由多个线程同时修改 Java API中似乎有三种不同的同步映射实现: Hashtable Collections.synchronizedMap(地图) ConcurrentHashMap 据我所知,Hashtable是一个旧的实现(扩展了过时的Dictionary类),后来进行了修改以适应Map接口。虽然它是同步的,但似乎有严重的问题,不鼓励新项目 但是另外两个呢?Collections.synchronizedMap(Map)和ConcurrentHashMaps返回的
Hashtable
Collections.synchronizedMap(地图)
ConcurrentHashMap
Hashtable
是一个旧的实现(扩展了过时的Dictionary
类),后来进行了修改以适应Map
接口。虽然它是同步的,但似乎有严重的问题,不鼓励新项目
但是另外两个呢?
Collections.synchronizedMap(Map)
和ConcurrentHashMap
s返回的映射之间有什么区别?哪一个适合哪种情况?根据您的需要,使用ConcurrentHashMap
。它允许从多个线程并发修改映射,而无需阻止它们<代码>集合。synchronizedMap(map)会创建一个阻塞映射,这会降低性能,但会确保一致性(如果使用正确)
如果需要确保数据一致性,并且每个线程都需要有地图的最新视图,请使用第二个选项。如果性能非常关键,并且每个线程只向映射插入数据,读取的频率较低,则使用第一个线程。如果可以使用ConcurrentHashMap,则首选ConcurrentHashMap,尽管它至少需要Java 5 它被设计成在多线程使用时可以很好地伸缩。当一次只有一个线程访问Map时,性能可能会稍差,但当多个线程同时访问Map时,性能会显著提高 我找到了一张复制了这本好书的桌子的桌子,我完全推荐这本书
Collections.synchronizedMap只有在您需要使用其他一些特征(可能是某种有序映射,如树形映射)来包装映射时才有意义。
- 并且不允许使用
键或null
值null
- 同步所有操作(
、get
、put
等)size
- 支持检索的完全并发性和更新的可调整预期并发性
和往常一样,还涉及到并发性(开销)和速度权衡。您确实需要考虑应用程序的详细并发需求来作出决定,然后测试代码是否足够好。< /P>
CONCURNESHASMAP是为并发访问优化的。
访问不会锁定整个映射,而是使用更细粒度的策略,这提高了可伸缩性。还有一些专门针对并发访问的功能增强,例如并发迭代器。您对哈希表的看法是正确的,您可以忽略它 提到虽然HashTable和synchronized wrapper类通过一次只允许一个线程访问映射来提供基本的线程安全性,但这不是“真正的”线程安全性,因为许多复合操作仍然需要额外的同步,例如:
synchronized (records) {
Record rec = records.get(id);
if (rec == null) {
rec = new Record(id);
records.put(id, rec);
}
return rec;
}
但是,不要认为ConcurrentHashMap
是具有如上所示的典型synchronized
块的HashMap
的简单替代方案。阅读文章以更好地理解其复杂性。哈希表的“可伸缩性问题”在集合中以完全相同的方式出现。synchronizedMap(Map)
-它们使用非常简单的同步,这意味着只有一个线程可以同时访问映射
当您进行简单的插入和查找时,这不是什么大问题(除非您进行了非常密集的插入和查找),但当您需要迭代整个映射时,这会成为一个大问题,对于一个大型映射,这可能需要很长的时间-当一个线程执行此操作时,所有其他线程都必须等待,如果他们想要插入或查找任何内容
ConcurrentHashMap
使用非常复杂的技术来减少同步需求,允许多线程在不同步的情况下进行并行读取访问,更重要的是,它提供了一个不需要同步的迭代器,甚至允许在交互过程中修改映射(虽然它不能保证在迭代过程中插入的元素是否会被返回)。一般来说,如果您想使用ConcurrentHashMap
请确保您准备好错过“更新”
(即,打印HashMap的内容并不保证它会打印最新的映射)并使用类似于CyclicBarrier
的API来确保整个程序生命周期的一致性。以下是一些:
1) ConcurrentHashMap只锁定映射的一部分,而SynchronizedMap锁定整个映射。
2) ConcurrentHashMap比SynchronizedMap具有更好的性能和更大的可扩展性。
3) 在多个读卡器和单个写卡器的情况下,ConcurrentHashMap是最佳选择
此文本来自ConcurrentHashMap
中的,锁应用于段而不是整个映射。
每个段管理自己的内部哈希表。锁定仅应用于更新操作<代码>集合。同步地图(地图)
同步整个地图
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║ 财产║ 哈希映射║ 哈希表║ ConcurrentHashMap║
╠═══════════════╬═══
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}
private static class SynchronizedMap<K,V>
implements Map<K,V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L;
private final Map<K,V> m; // Backing Map
final Object mutex; // Object on which to synchronize
SynchronizedMap(Map<K,V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
}
SynchronizedMap(Map<K,V> m, Object mutex) {
this.m = m;
this.mutex = mutex;
}
public int size() {
synchronized (mutex) {return m.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return m.isEmpty();}
}
public boolean containsKey(Object key) {
synchronized (mutex) {return m.containsKey(key);}
}
public boolean containsValue(Object value) {
synchronized (mutex) {return m.containsValue(value);}
}
public V get(Object key) {
synchronized (mutex) {return m.get(key);}
}
public V put(K key, V value) {
synchronized (mutex) {return m.put(key, value);}
}
public V remove(Object key) {
synchronized (mutex) {return m.remove(key);}
}
public void putAll(Map<? extends K, ? extends V> map) {
synchronized (mutex) {m.putAll(map);}
}
public void clear() {
synchronized (mutex) {m.clear();}
}
private transient Set<K> keySet;
private transient Set<Map.Entry<K,V>> entrySet;
private transient Collection<V> values;
public Set<K> keySet() {
synchronized (mutex) {
if (keySet==null)
keySet = new SynchronizedSet<>(m.keySet(), mutex);
return keySet;
}
}
public Set<Map.Entry<K,V>> entrySet() {
synchronized (mutex) {
if (entrySet==null)
entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
return entrySet;
}
}
public Collection<V> values() {
synchronized (mutex) {
if (values==null)
values = new SynchronizedCollection<>(m.values(), mutex);
return values;
}
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return m.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return m.hashCode();}
}
public String toString() {
synchronized (mutex) {return m.toString();}
}
// Override default methods in Map
@Override
public V getOrDefault(Object k, V defaultValue) {
synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
}
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
synchronized (mutex) {m.forEach(action);}
}
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
synchronized (mutex) {m.replaceAll(function);}
}
@Override
public V putIfAbsent(K key, V value) {
synchronized (mutex) {return m.putIfAbsent(key, value);}
}
@Override
public boolean remove(Object key, Object value) {
synchronized (mutex) {return m.remove(key, value);}
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
synchronized (mutex) {return m.replace(key, oldValue, newValue);}
}
@Override
public V replace(K key, V value) {
synchronized (mutex) {return m.replace(key, value);}
}
@Override
public V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
}
@Override
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
}
@Override
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
synchronized (mutex) {return m.compute(key, remappingFunction);}
}
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
synchronized (mutex) {return m.merge(key, value, remappingFunction);}
}
private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();}
}
}