Java中的ConcurrentHashMap?
在java中使用并发哈希映射是什么? 它有什么好处? 它是如何工作的? 请帮助…示例代码也是有用的..
重点是提供一个线程安全的HashMap
的实现。 multithreading可以读取和写入,而不会收到过时或损坏的数据。 ConcurrentHashMap
提供了自己的同步,所以你不必显式地同步访问。
ConcurrentHashMap
另一个特性是它提供了putIfAbsent
方法,如果指定的键不存在,它将自动添加一个映射。 考虑下面的代码:
ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>(); // some stuff if (!myMap.contains("key")) { myMap.put("key", 3); }
这段代码不是线程安全的,因为另一个线程可以在调用contains
和put
的调用之间添加一个"key"
的映射。 正确的实施将是:
myMap.putIfAbsent("key", 3);
ConcurrentHashMap
允许并发访问地图。 哈希表也提供对地图的同步访问,但整个地图被locking以执行任何操作。
ConcurrentHashMap背后的逻辑是your entire table is not getting locked
,只有部分[ segments
]。 每个分段pipe理自己的HashTable。 locking仅适用于更新。 在检索的情况下,它允许完全并发。
让我们拿四个线程同时在一个容量为32的映射上工作,该表被分成四个段,每段pipe理一个容量哈希表。 该集合默认维护一个16个分段的列表,每个分段用于保护(或locking)地图的一个桶。
这实际上意味着16个线程可以一次修改集合。 可以使用可选的concurrencyLevel构造函数参数来增加此级别的并发性 。
public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)
正如另一个答案所述,ConcurrentHashMap提供了与put相似的新方法putIfAbsent()
,只是如果密钥存在,值不会被覆盖。
private static Map<String,String> aMap =new ConcurrentHashMap<String,String>(); if(!aMap.contains("key")) aMap.put("key","value");
新的方法也更快,因为它避免了如上所述的double traversing
。 contains
方法必须定位段并迭代表来find关键字,并且方法put
必须遍历存储段并放置关键字。
真的很大的function差异是它不会抛出exception和/或最终腐败时,别人改变它,而你使用它。
对于常规集合,如果另一个线程在访问它时(通过迭代器)添加或删除元素,则会抛出exception。 ConcurrentHashMap让他们做出改变,不会停止你的线程。
请注意,它没有对从一个线程到另一个线程的变化的时间点可见性做出任何forms的同步保证或承诺。 (这有点像读取提交的数据库隔离,而不是一个同步映射,其行为更像一个可序列化的数据库隔离(旧学校行锁SQL可序列化,而不是Oracle-ISH多版本可串行化:))
我所知道的最常见的用途是在App Server环境中caching不可变的派生信息,在这些环境中,许multithreading可能访问同一个事物,而且如果两个事件计算相同的caching值并放置两次, (例如,它广泛用于Spring WebMVC框架中,用于保存从URL到Handler方法的映射等运行时派生的configuration)。
它可以用于记忆:
import java.util.concurrent.ConcurrentHashMap; public static Function<Integer, Integer> fib = (n) -> { Map<Integer, Integer> cache = new ConcurrentHashMap<>(); if (n == 0 || n == 1) return n; return cache.computeIfAbsent(n, (key) -> HelloWorld.fib.apply(n - 2) + HelloWorld.fib.apply(n - 1)); };
1.ConcurrentHashMap是线程安全的,即代码可以一次由单个线程访问。
2.ConcurrentHashMap同步或lockingMap的某个部分。 为了优化ConcurrentHashMap的性能,Map根据并发级别分为不同的分区。 所以我们不需要同步整个Map对象。
3.默认并发级别为16,因此映射被分成16个部分,每个部分被不同的锁pipe理,这意味着16个线程可以操作。
4.ConcurrentHashMap不允许NULL值。 因此,ConcurrentHashMap中的键不能为空。