Java中的ConcurrentHashMap?

Pra*_*een 56 java concurrenthashmap

ConcurrentHashMap在Java中有什么用?它有什么好处?它是如何工作的?示例代码也很有用.

dan*_*ben 71

关键是提供HashMap线程安全的实现.多个线程可以读取和写入它,而不会接收到过时或损坏的数据. ConcurrentHashMap提供自己的同步,因此您不必显式同步对它的访问.

另一个特性ConcurrentHashMap是它提供了putIfAbsent方法,如果指定的键不存在,它将以原子方式添加映射.请考虑以下代码:

ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>();

// some stuff

if (!myMap.contains("key")) {
  myMap.put("key", 3);
}
Run Code Online (Sandbox Code Playgroud)

此代码不是线程安全的,因为另一个线程可以"key"在调用contains和调用之间添加映射put.正确的实施将是:

myMap.putIfAbsent("key", 3);
Run Code Online (Sandbox Code Playgroud)

  • 我会把它描述为"安全不同步".它允许两个线程同时在内部进行混乱,并且有望在之后以一致的状态结束. (7认同)
  • 同步不是(外部)排序保证. (6认同)
  • 这不是一个保证线程请求监控器将收到所要求的顺序,但它是一个之前发生的保证,一旦一个线程获得监视器,并开始修改地图,没有人会看到它,直到修改完成.在并发映射中,一个线程可以启动一个put,然后很长时间没有再次调度,而其他线程可以执行不会看到正在进行的put. (5认同)

Tha*_*var 30

ConcurrentHashMap允许并发访问地图.HashTables也提供对地图的同步访问,但您的整个地图都被锁定以执行任何操作.

ConcurrentHashMap背后的逻辑是your entire table is not getting locked,但只有部分[ segments].每个细分都管理自己的HashTable.锁定仅适用于更新.在检索的情况下,它允许完全并发.

让我们将四个线程同时在一个容量为32的映射上工作,该表被分成四个段,每个段管理一个容量哈希表.该集合默认维护一个包含16个段的列表,每个段用于保护(或锁定)地图的单个存储桶.

在此输入图像描述

这实际上意味着16个线程可以一次修改集合.使用可选的concurrencyLevel构造函数参数可以增加此并发级别.

public ConcurrentHashMap(int initialCapacity,
                         float loadFactor, int concurrencyLevel)
Run Code Online (Sandbox Code Playgroud)

正如另一个答案所述,ConcurrentHashMap提供了putIfAbsent()类似于put的新方法,除非键存在时不会覆盖该值.

private static Map<String,String> aMap =new ConcurrentHashMap<String,String>();

if(!aMap.contains("key"))
   aMap.put("key","value");
Run Code Online (Sandbox Code Playgroud)

新方法也更快,因为它避免double traversing了如上所述.contains方法必须定位段并迭代表以找到密钥,并且方法put必须再次遍历桶并放置密钥.


Aff*_*ffe 12

实际上,最大的功能区别在于,当您使用它时,当其他人更改它时,它不会抛出异常和/或最终损坏.

对于常规集合,如果另一个线程在您访问它时(通过迭代器)添加或删除元素,则会抛出异常.ConcurrentHashMap允许他们进行更改并且不会停止您的线程.

请注意,它不会对从一个线程到另一个线程的更改的时间点可见性做出任何形式的同步保证或承诺.(它有点像读取提交的数据库隔离,而不是同步映射,其行为更像是可序列化的数据库隔离.(旧学校行锁定SQL可序列化,而不是Oracle-ish multiversion序列化:))

我所知道的最常见的用途是在App Server环境中缓存不可变的派生信息,其中许多线程可能正在访问同一个东西,并且如果两个碰巧计算相同的缓存值并将它放两次因为它们交错并不重要等等(例如,它在Spring WebMVC框架内广泛使用,用于保存运行时派生的配置,如从URL到Handler方法的映射.)