繁体   English   中英

Java中的ConcurrentHashMap?

[英]ConcurrentHashMap in Java?

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

重点是提供线程安全的HashMap实现。 多个线程可以读取和写入它,而不会接收过时或损坏的数据。 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允许并发访问地图。 HashTables也提供对地图的同步访问,但您的整个地图都被锁定以执行任何操作。

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

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

在此输入图像描述

这实际上意味着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方法必须定位段并迭代表以找到键,并且put方法必须再次遍历存储桶并放入密钥。

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

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

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

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

它可以用于记忆:

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同步或锁定Map的某个部分。 为了优化ConcurrentHashMap的性能,Map根据并发级别划分为不同的分区。 这样我们就不需要同步整个Map对象了。

3.Default并发级别为16,因此映射分为16个部分,每个部分由不同的锁管理,这意味着16个线程可以运行。

4.ConcurrentHashMap不允许NULL值。 所以在ConcurrentHashMap中键不能为null。

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

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

ConcurrentHashMap有一些关键点。

  • ConcurrentHashMap的Underling数据结构是HashTable。
  • ConcurrentHashMap是一个类,该类是线程安全的,它意味着多个线程可以访问单个线程对象而不会出现任何复杂情况。
  • ConcurretnHashMap对象根据并发级别划分为多个段。
  • ConcurrentHashMap的默认并发级别为16。
  • 在ConcurrentHashMap中,任意数量的Thread都可以执行检索操作,但是对于对象中的更新,Thread必须锁定线程想要操作的特定Segment。
  • 这种类型的锁定机构称为段锁定或铲斗锁定。
  • 在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); 
      } 
}  

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM