线程安全的集合有哪些_Java中的线程安全集合你知道吗?

点击蓝字

关注我们 FOLLOW US

ConcurrentHashMap类是在在JDK 1.5中引入的,属于java.util.concurrent包,它也实现了ConcurrentMap以及Serializable接口。ConcurrentHashMap是对HashMap的增强,因为我们知道在我们的应用程序中处理Threads时,HashMap并不是一个很好的选择,因为从性能上来说,HashMap并不符合要求。

ConcurrentHashMap的关键点:

  • ConcurrentHashMap的下划线数据结构是Hashtable。

  • ConcurrentHashMap类是线程安全的,即多个线程可以对一个对象进行操作,而不会产生任何复杂的问题。

  • 任何数量的线程都可以同时进行读取操作,而不会锁定ConcurrentHashMap对象,这在HashMap中是不存在的。

  • 在ConcurrentHashMap中,对象根据并发级别被划分为若干段。

  • ConcurrentHashMap的默认并发级别是16。

  • 在ConcurrentHashMap中,一次可以有任意多个线程进行检索操作,但对于对象中的更新,线程必须锁定该线程要操作的特定段。这种类型的锁定机制被称为分段锁或桶锁。因此每次线程可以进行16次更新操作。

  • 在ConcurrentHashMap中不可能插入Null作为键或值。

Declaration:

public class ConcurrentHashMap<K,•V> extends AbstractMap<K,•V> implements ConcurrentMap<K,•V>, Serializable

这里,K是键对象类型,V是值对象类型。

ConcurrentHashMap的层次结构

c3475016583e6b7c4c4df0b47a8737ce.png

它实现了 Serializable, ConcurrentMap, Map 接口,继承了AbstractMap

ConcurrentHashMap的构造函数

  • 并发级别 它是指同时更新地图的线程数量。实现中会执行内部大小调整,以尽量适应这个数量的线程。

  • Load-Factor(负载系数):这是一个阈值,用于控制大小调整。

  • 初始容量 是一个阈值,用来控制调整大小。如果这个地图的容量是10,就意味着它可以存储10个条目。就意味着它可以存储10个条目。

1. ConcurrentHashMap() : 创建一个新的空Map,默认初始容量(16)、负载因子(0.75)和并发级别(16)。

ConcurrentHashMap<K, V> chm = new ConcurrentHashMap<>();

2. ConcurrentHashMap(int initialCapacity) : 用指定的初始容量创建一个新的空Map,并使用默认的负载因子(0.75)和并发级别(16)。

ConcurrentHashMap chm = new ConcurrentHashMap<>(int initialCapacity);

3. ConcurrentHashMap(int initialCapacity, float loadFactor) : 用指定的初始容量和负载因子以及默认的并发级别(16)创建一个新的空Map。

ConcurrentHashMap chm = new ConcurrentHashMap<>(int initialCapacity, float loadFactor);

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

ConcurrentHashMap chm = new ConcurrentHashMap<>(int initialCapacity, float loadFactor, int concurrencyLevel);

5. ConcurrentHashMap(Map m); 创建一个与给定ConcurrentHashMap相同的新Map。

ConcurrentHashMap chm = new ConcurrentHashMap<>(Map m);

Example:

// Java program to demonstrate working of ConcurrentHashMap import java.util.concurrent.*; class ConcurrentHashMapDemo {   public static void main(String[] args)   {     // create an instance of     // ConcurrentHashMap     ConcurrentHashMap m = new ConcurrentHashMap<>();           // Insert mappings using     // put method     m.put(100, "Hello");     m.put(101, "Geeks");     m.put(102, "Geeks");     // Here we cant add Hello because 101 key     // is already present in ConcurrentHashMap object     m.putIfAbsent(101, "Hello");     // We can remove entry because 101 key     // is associated with For value     m.remove(101, "Geeks");     // Now we can add Hello     m.putIfAbsent(103, "Hello");     // We cant replace Hello with For     m.replace(101, "Hello", "For");     System.out.println(m);   } } 

Output:

{100=Hello, 102=Geeks, 103=Hello}

ConcurrentHashMap常用操作

1. 添加元素

要将映射数据插入到一个ConcurrentHashMap中,我们可以使用put()putAll()方法。下面的示例代码解释了这两种方法。

// Java program to demonstrate adding // elements to the ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap; import java.util.*; public class AddingElementsToConcuurentHashMap {   public static void main(String[] args)   {     // Creating ConcurrentHashMap     ConcurrentHashMap<String, String> my_cmmap       = new ConcurrentHashMap<String, String>();     // Adding elements to the map     // using put() method     my_cmmap.put("1", "1");     my_cmmap.put("2", "1");     my_cmmap.put("3", "1");     my_cmmap.put("4", "1");     my_cmmap.put("5", "1");     my_cmmap.put("6", "1");     // Printing the map     System.out.println("Mappings of my_cmmap : "            + my_cmmap);     // create another concurrentHashMap     ConcurrentHashMap<String, String> new_chm       = new ConcurrentHashMap<>();     // copy mappings from my_cmmap to new_chm     new_chm.putAll(my_cmmap);     // Displaying the new map     System.out.println("New mappings are: " + new_chm);   } }

Output

Mappings of my_cmmap : {1=1, 2=1, 3=1, 4=1, 5=1, 6=1}New mappings are: {1=1, 2=1, 3=1, 4=1, 5=1, 6=1}

2. 删除元素

要删除一个映射,我们可以使用 ConcurrentHashmap 类的 remove(Object key) 方法。如果key在map中不存在,那么这个函数什么也不做。要清除整个映射,我们可以使用clear()方法。

// Java program to demonstrate removing // elements from ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap; import java.util.*; public class RemoveElementsFromConcurrentHashMap {   public static void main(String[] args)   {     // Creating ConcurrentHashMap     Map my_cmmap = new ConcurrentHashMap();     // Adding elements to the map     // using put() method     my_cmmap.put("1", "1");     my_cmmap.put("2", "1");     my_cmmap.put("3", "1");     my_cmmap.put("4", "1");     my_cmmap.put("5", "1");     my_cmmap.put("6", "1");     // Printing the map     System.out.println("Map: " + my_cmmap);     System.out.println();     // Removing the mapping     // with existing key 6     // using remove() method     String valueRemoved = my_cmmap.remove("6");     // Printing the map after remove()     System.out.println("After removing mapping with key 6:");     System.out.println("Map: " + my_cmmap);     System.out.println("Value removed: "            + valueRemoved);     System.out.println();     // Removing the mapping     // with non-existing key 10     // using remove() method     valueRemoved = my_cmmap.remove("10");     // Printing the map after remove()     System.out.println(       "After removing mapping with key 10:");     System.out.println("Map: " + my_cmmap);     System.out.println("Value removed: "            + valueRemoved);     System.out.println();     // Now clear the map using clear()     my_cmmap.clear();     // Print the clea Map     System.out.println("Map after use of clear(): "            + my_cmmap);   } }

Output

Map: {1=1, 2=1, 3=1, 4=1, 5=1, 6=1}After removing mapping with key 6:Map: {1=1, 2=1, 3=1, 4=1, 5=1}Value removed: 1After removing mapping with key 10:Map: {1=1, 2=1, 3=1, 4=1, 5=1}Value removed: nullMap after use of clear(): {}

3. 获取元素

我们可以使用get()方法来访问一个ConcurrentHashMap的元素,下面给出了这个例子。

// Java Program Demonstrate accessing // elements of ConcurrentHashMap import java.util.concurrent.*; class AccessingElementsOfConcurrentHashMap {   public static void main(String[] args)   {     // create an instance of ConcurrentHashMap     ConcurrentHashMap chm       = new ConcurrentHashMap();     // insert mappings using put method     chm.put(100, "Geeks");     chm.put(101, "for");     chm.put(102, "Geeks");     chm.put(103, "Contribute");     // Displaying the HashMap     System.out.println("The Mappings are: ");     System.out.println(chm);     // Display the value of 100     System.out.println("The Value associated to "            + "100 is : " + chm.get(100));     // Getting the value of 103     System.out.println("The Value associated to "            + "103 is : " + chm.get(103));   } }

Output

The Mappings are: {100=Geeks, 101=for, 102=Geeks, 103=Contribute}The Value associated to 100 is : GeeksThe Value associated to 103 is : Contribute

4. 遍历

我们可以使用Iterator接口来遍历Collection Framework的任何结构。由于Iterators只处理一种类型的数据,我们使用Entry< ? , ? > 将两种不同类型的数据解析成兼容的格式。然后使用 next() 方法打印 ConcurrentHashMap 的元素。

// Java Program for traversing a // ConcurrentHashMap import java.util.concurrent.*; import java.util.*; public class TraversingConcurrentHashMap {   public static void main(String[] args)   {     // create an instance of ConcurrentHashMap     ConcurrentHashMapString> chmap       = new ConcurrentHashMapString>();     // Add elements using put()     chmap.put(8, "Third");     chmap.put(6, "Second");     chmap.put(3, "First");     chmap.put(11, "Fourth");     // Create an Iterator over the     // ConcurrentHashMap     IteratorString> >       itr = chmap.entrySet().iterator();     // The hasNext() method is used to check if there is     // a next element The next() method is used to     // retrieve the next element     while (itr.hasNext()) {       ConcurrentHashMap.EntryString> entry         = itr.next();       System.out.println("Key = " + entry.getKey()               + ", Value = "              + entry.getValue());     }   } }

Output

Key = 3, Value = FirstKey = 6, Value = SecondKey = 8, Value = ThirdKey = 11, Value = Fourth

Methods of ConcurrentHashMap

  • K – Map集合中键的类型

  • V – Map中映射的值的类型。

METHODDESCRIPTION
clear()移除此Map上的所有键值对。
compute(K key, BiFunction remappingFunction)试图计算指定键及其当前映射值的映射(如果没有当前映射,则为空)。
computeIfAbsent(K key, Function mappingFunction)如果指定的键还没有与值相关联,则尝试使用给定的映射函数计算其值,并将其输入到这个映射中,除非为空。
computeIfPresent(K key, BiFunction super K,? super V,? extends V> remappingFunction)如果指定键的值存在,则尝试根据键及其当前映射值计算新的映射。
contains(Object value)测试某个键是否映射到本表的指定值中。
containsKey(Object key)测试指定的对象是否是本集合中的键。
containsValue(Object value)如果此映射将一个或多个键映射到指定的值,则返回true。
elements()返回本表中数值的枚举。
entrySet()返回该地图中包含的映射的Set视图。
equals(Object o)将指定的对象与此图进行平等比较。
forEach(long parallelismThreshold, BiConsumer super K,? super V> action)对每个(键,值)执行给定的操作。
forEach(long parallelismThreshold, BiFunction super K,? super V,? extends U> transformer, Consumer super U> action)对每个(键,值)的非空变换执行给定的操作。
forEachEntry(long parallelismThreshold, Consumer super Map.Entry> action)对每个条目执行指定的操作。
forEachEntry(long parallelismThreshold, Function,? extends U> transformer, Consumer super U> action)对每个条目的非空变换执行给定动作。
forEachKey(long parallelismThreshold, Consumer super K> action)Performs the given action for each key.
forEachKey(long parallelismThreshold, Function super K,? extends U> transformer, Consumer super U> action)Performs the given action for each non-null transformation of each key.
forEachValue(long parallelismThreshold, Consumer super V> action)Performs the given action for each value.
forEachValue(long parallelismThreshold, Function super V,? extends U> transformer, Consumer super U> action)Performs the given action for each non-null transformation of each value.
get(Object key)返回指定键的映射值,如果该映射不包含键的映射,则返回空值。
getOrDefault(Object key, V defaultValue)Returns the value to which the specified key is mapped, or the given default value if this map contains no mapping for the key.
hashCode()返回此Map的哈希码值,即Map中每个键值对的key.hashCode() ^ value.hashCode()之和。
keys()返回本表中键的枚举。
keySet()返回此地图中的键值的Set视图。
keySet(V mappedValue)Returns a Set view of the keys in this map, using the given common mapped value for any additions (i.e., Collection.add(E) and Collection.addAll(Collection)).
mappingCount()Returns the number of mappings.
merge(K key, V value, BiFunction super V,? super V,? extends V> remappingFunction)If the specified key is not already associated with a (non-null) value, associates it with the given value.
newKeySet()Creates a new Set backed by a ConcurrentHashMap from the given type to Boolean.TRUE.
newKeySet(int initialCapacity)Creates a new Set backed by a ConcurrentHashMap from the given type to Boolean.TRUE.
put(K key, V value)将指定的键映射到本表的指定值上。
putAll(Map m)将指定地图上的所有映射复制到这个地图上。
putIfAbsent(K key, V value)如果指定的键没有与值关联,则将其与给定的值关联。
remove(Object key)从该地图中删除键(和其对应的值)。
remove(Object key, Object value)只有在当前映射到给定值的情况下,才会删除某个键的条目。
values()返回该Map中包含的值的集合视图。

java.util.AbstractMap类中方法的定义

METHODDESCRIPTION
clone()返回这个AbstractMap实例的一个浅复制:键和值本身不会被克隆。
isEmpty()如果该Map不包含键值对,则返回true。
size()返回该Map中键值对的数量。

java.util.concurrent.ConcurrentMap接口中方法的定义

METHODDESCRIPTION
forEach(BiConsumer super K,? super V> action)对Map中的每个条目执行给定的操作,直到所有的条目都被处理完,或者该操作引发一个异常。
replaceAll(BiFunction super K,? super V,? extends V> function)用在该条目上调用给定函数的结果替换每个条目的值,直到所有条目都被处理完毕或函数引发异常。

Must Read: Difference between HashMap and ConcurrentHashMap

ConcurrentHashMap vs Hashtable

HashTable

  • Hashtable  是Map数据结构的实现

  • 这是一个遗留类,其中所有方法都是在Hashtable实例上使用synchronized关键字进行同步。

  • 由于它的方法是同步的,所以是线程安全的。

ConcurrentHashMap

  • ConcurrentHashMap  实现了Map数据结构,也提供了像Hashtable一样的线程安全。

  • 它的工作原理是将完整的哈希数组划分为片段或部分,并允许对这些片段进行并行访问。

  • 锁是在一个更细粒度的哈希桶。

  • 当你的程序中需要非常高的并发性时,请使用ConcurrentHashMap

  • 它是一个不需要同步整个Map的线程安全。

  • 读取可以非常快地进行,而写入则是在段级或桶级上加锁完成。

  • 在对象级别上没有锁。

  • 如果一个线程试图在另一个线程迭代时修改它,ConcurrentHashMap不会抛出ConcurrentModificationException

  • ConcurrentHashMap不允许NULL值,所以在ConcurrentHashMap中key不能为空。

  • 如果一个线程试图修改它,而另一个线程正在迭代它,ConcurrentHashMap不会抛出一个并发修改异常

PROPERTIESHASHTABLECONCURRENTHASHMAP
CreationMap ht = new Hashtable();  Map chm = new ConcurrentHashMap();
Is Null Key Allowed ?NoNo
Is Null Value Allowed ?NoYes
Is Thread Safe ?YesYes, Thread safety is ensured by having separate locks for separate buckets, resulting in better performance. Performance is further improved by providing read access concurrently without any blocking.
PerformanceSlow due to synchronization overhead.Faster than Hashtable. ConcurrentHashMap is a better choice when there are more reads than writes.
IteratorHashtable uses enumerator to iterate the values of Hashtable object. Enumerations returned by the Hashtable keys and elements methods are not fail-fast.Fail-safe iterator: Iterator provided by the ConcurrentHashMap is fail-safe, which means it will not throw ConcurrentModificationException.

结论:

  • 如果需要一个线程安全的高并发实现,那么建议使用ConcurrentHashMap来代替Hashtable

991ad1c69d6f843ddecdcdad3e5a65ab.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值