61

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

4

6 回答 6

76

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

的另一个特点ConcurrentHashMap是它提供了方法,如果指定的键不存在putIfAbsent,它将自动添加映射。考虑以下代码:

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

// some stuff

if (!myMap.contains("key")) {
  myMap.put("key", 3);
}

这段代码不是线程安全的,因为另一个线程可以在调用和调用"key"之间添加一个映射。正确的实现是:containsput

myMap.putIfAbsent("key", 3);
于 2010-05-14T17:36:50.297 回答
31

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

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

让我们假设四个线程同时处理容量为 32 的映射,该表被划分为四个段,每个段管理一个容量哈希表。默认情况下,该集合维护一个包含 16 个段的列表,每个段用于保护(或锁定)地图的单个存储桶。

在此处输入图像描述

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

public ConcurrentHashMap(int initialCapacity,
                         float loadFactor, int concurrencyLevel)

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

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

if(!aMap.contains("key"))
   aMap.put("key","value");

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

于 2013-09-27T23:35:05.707 回答
12

真正最大的功能差异是它不会引发异常和/或在您使用它时其他人更改它时最终损坏。

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

请注意,它不会对从一个线程到另一个线程的更改的时间点可见性做出任何类型的同步保证或承诺。(它有点像已提交读的数据库隔离,而不是表现得更像可序列化数据库隔离的同步映射。(老派的行锁定 SQL 可序列化,而不是 Oracle-ish 多版本可序列化 :))

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

于 2010-05-14T17:38:04.587 回答
4

它可用于记忆:

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));
};
于 2015-01-03T02:48:40.693 回答
1

1.ConcurrentHashMap是线程安全的,即代码一次可以被单个线程访问。

2.ConcurrentHashMap 同步或锁定 Map 的特定部分。为了优化 ConcurrentHashMap 的性能,Map 根据并发级别划分为不同的分区。这样我们就不需要同步整个 Map Object。

3.默认并发级别为16,因此map被分为16个部分,每个部分由不同的锁控制,即16个线程可以操作。

4.ConcurrentHashMap不允许NULL值。因此 ConcurrentHashMap 中的键不能为空。

于 2017-09-08T18:30:06.060 回答
0

大家好,今天我们讨论了 ConcurrentHashMap。
什么是 ConcurrentHashMap?

ConcurrentHashMap 是它在 java 1.5 中引入的一个类,它实现了 ConcurrentMap 以及 Serializable 接口。ConcurrentHashMap 在处理多个 Theading 时增强了 HashMap。正如我们所知,当应用程序有多个线程时,HashMap 并不是一个好的选择,因为会出现性能问题。

ConcurrentHashMap有一些关键点。

  • ConcurrentHashMap 的底层数据结构是 HashTable。
  • ConcurrentHashMap 是一个类,该类是线程安全的,这意味着多个线程可以在单个线程对象上访问而没有任何复杂性。
  • ConcurretnHashMap 对象根据并发级别划分为多个段。
  • ConcurrentHashMap 的默认并发级别为 16。
  • 在 ConcurrentHashMap 中任意数量的 Thread 都可以执行检索操作,但是对于对象中的更新,Thread 必须锁定线程要操作的特定 Segment。
  • 这种类型的锁定机制称为 Segment-Locking 或 Bucket-Locking。
  • 在 ConcurrentHashMap 中,一次执行 16 个更新操作。
  • 在 ConcurrentHashMap 中不能插入空值。

这是 ConcurrentHashMap 的构造。

  1. ConcurrentHashMap m=new ConcurrentHashMap();:创建一个具有默认初始容量 (16)、负载因子 (0.75) 和 concurrencyLevel (16) 的新空映射。

  2. ConcurrentHashMap m=new ConcurrentHashMap(int initialCapacity);:创建一个具有指定初始容量、默认加载因子 (0.75) 和 concurrencyLevel (16) 的新空映射。

  3. ConcurrentHashMap m=new ConcurrentHashMap(int initialCapacity, float loadFactor);:使用指定的初始容量和加载因子以及默认的 concurrencyLevel (16) 创建一个新的空映射。

  4. ConcurrentHashMap m=new ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel);:使用指定的初始容量、负载因子和并发级别创建一个新的空映射。

  5. ConcurrentHashMap m=new ConcurrentHashMap(Map m);:创建一个与给定映射具有相同映射的新映射。

ConcurretHashMap 有一个名为putIfAbsent() 的方法;该方法是防止存储重复密钥,请参考下面的示例。

    import java.util.concurrent.*; 

     class ConcurrentHashMapDemo { 
     public static void main(String[] args) 
     { 
         ConcurrentHashMap m = new ConcurrentHashMap(); 
          m.put(1, "Hello"); 
          m.put(2, "Vala"); 
          m.put(3, "Sarakar"); 

         // Here we cant add Hello because 1 key 
         // is already present in ConcurrentHashMap object 

            m.putIfAbsent(1, "Hello"); 

         // We can remove entry because 2 key 
         // is associated with For value 

            m.remove(2, "Vala"); 

        // Now we can add Vala

            m.putIfAbsent(4, "Vala"); 


            System.out.println(m); 
      } 
}  
于 2019-05-10T04:27:44.977 回答