先决条件: ConcurrentMap
这个 ConcurrentHashMap 类是在JDK 1.5所属的 JAVAutil。同时发生的 包,它实现了ConcurrentMap以及可序列化接口。ConcurrentHashMap是HashMap的一个增强,因为我们知道,在应用程序中处理线程时,HashMap不是一个好的选择,因为性能方面的HashMap没有达到标准。
ConcurrentHashMap的要点:
- ConcurrentHashMap的下划线数据结构为 哈希表 .
- ConcurrentHashMap类是线程安全的,即多个线程可以在单个对象上操作,而不会出现任何复杂情况。
- 一次,任何数量的线程都适用于读取操作,而无需锁定HashMap中不存在的ConcurrentHashMap对象。
- 在ConcurrentHashMap中,根据并发级别将对象划分为若干段。
- ConcurrentHashMap的默认并发级别为16。
- 在ConcurrentHashMap中,每次任何数量的线程都可以执行检索操作,但对于对象中的更新,线程必须锁定线程想要操作的特定段。这种锁紧机构被称为 分段锁定或铲斗锁定 。因此,线程一次可以执行16个更新操作。
- 在ConcurrentHashMap中不能将空对象作为键或值插入。
宣言:
公共类ConcurrentHashMap
扩展抽象映射 实现ConcurrentMap ,可序列化
在这里 K 是键对象类型和 五、 是值对象类型。
ConcurrentHashMap的层次结构
它实现了 可序列化 , ConcurrentMap
ConcurrentHashMap的构造函数
- 并发级别: 它是同时更新映射的线程数。该实现执行内部大小调整以尝试容纳这么多线程。
- 荷载系数: 这是一个阈值,用于控制大小调整。
- 初始容量: 容纳最初由实施提供的一定数量的要素。如果这张地图的容量是10。这意味着它可以存储10个条目。
1.ConcurrentHashMap() :创建具有默认初始容量(16)、负载系数(0.75)和并发级别(16)的新空映射。
ConcurrentHashMap
chm=新的ConcurrentHashMap<>();
2.ConcurrentHashMap(int initialCapacity) :创建具有指定初始容量、默认负载系数(0.75)和并发级别(16)的新空映射。
ConcurrentHashMap
chm=新的ConcurrentHashMap<>(int initialCapacity);
3.ConcurrentHashMap(int initialCapacity,float loadFactor) :使用指定的初始容量和负载系数以及默认的并发级别(16)创建一个新的空映射。
ConcurrentHashMap
chm=新的ConcurrentHashMap<>(int initialCapacity,float loadFactor);
4.ConcurrentHashMap(int initialCapacity,float loadFactor,int concurrentyLevel) :使用指定的初始容量、负载系数和并发级别创建新的空映射。
ConcurrentHashMap
chm=新的ConcurrentHashMap<>(int initialCapacity,float loadFactor,int concurrentyLevel);
5.ConcurrentHashMap(Map m) :使用与给定映射相同的映射创建新映射。
ConcurrentHashMap
chm=新的ConcurrentHashMap<>(Map m);
例子:
JAVA
// 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<Integer, String> 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); } } |
{100=Hello, 102=Geeks, 103=Hello}
ConcurrentHashMap上的基本操作
1.添加元素
要将映射插入ConcurrentHashMap,我们可以使用 put() 或 putAll() 方法。下面的示例代码解释了这两种方法。
JAVA
// Java program to demonstrate adding // elements to the ConcurrentHashMap import java.util.*; import java.util.concurrent.ConcurrentHashMap; 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); } } |
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的方法。如果该键在地图中不存在,则此函数不起任何作用。要清除整个地图,我们可以使用 清除() 方法
JAVA
// Java program to demonstrate removing // elements from ConcurrentHashMap import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class RemoveElementsFromConcurrentHashMap { public static void main(String[] args) { // Creating ConcurrentHashMap Map<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( "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); } } |
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.访问元素
我们可以使用 得到() 方法,下面给出了该方法的示例。
JAVA
// 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<Integer, String> chm = new ConcurrentHashMap<Integer, String>(); // 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 )); } } |
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.穿越
我们可以使用 迭代器 接口来遍历集合框架的任何结构。因为迭代器处理一种类型的数据,所以我们使用Entry将这两种不同的类型解析为兼容的格式。然后使用next()方法打印ConcurrentHashMap的元素。
JAVA
// Java Program for traversing a // ConcurrentHashMap import java.util.*; import java.util.concurrent.*; public class TraversingConcurrentHashMap { public static void main(String[] args) { // create an instance of ConcurrentHashMap ConcurrentHashMap<Integer, String> chmap = new ConcurrentHashMap<Integer, String>(); // 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 Iterator<ConcurrentHashMap.Entry<Integer, String> > 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.Entry<Integer, String> entry = itr.next(); System.out.println( "Key = " + entry.getKey() + ", Value = " + entry.getValue()); } } } |
Key = 3, Value = FirstKey = 6, Value = SecondKey = 8, Value = ThirdKey = 11, Value = Fourth
ConcurrentHashMap方法
- K –地图上钥匙的类型。
- 五、 –映射到映射中的值的类型。
方法 |
描述 |
---|---|
清除() | 删除此映射中的所有映射。 |
计算(K键,双功能重新映射功能) | 尝试计算指定键及其当前映射值的映射(如果没有当前映射,则为null)。 |
计算机(K键,功能映射功能) | 如果指定的键尚未与值关联,则尝试使用给定的映射函数计算其值,并将其输入此映射,除非为null。 |
计算机呈现(K键,双功能重新映射功能) | 如果指定键的值存在,则尝试在给定键及其当前映射值的情况下计算新映射。 |
包含(对象值) | 测试某些键是否映射到此表中的指定值。 |
康纳斯基(对象键) | 测试指定的对象是否是此表中的键。 |
包含价值(对象值) | 如果此映射将一个或多个键映射到指定值,则返回true。 |
元素() | 返回此表中值的枚举。 |
入口集() | 返回此映射中包含的映射的集合视图。 |
等于(对象o) | 将指定的对象与此映射进行相等性比较。 |
弗雷奇(长并行阈值,双消费者动作) | 对每个(键、值)执行给定的操作。 |
弗雷奇(长并行阈值,双功能变压器,耗电元件动作) | 对每个(键、值)的每个非空转换执行给定的操作。 |
外国进入(长平行度阈值,消费者 >行动) | 对每个条目执行给定的操作。 |
外国进入(长并行性阈值,函数 |
对每个条目的每个非空转换执行给定的操作。 |
forEachKey(长并行阈值,消费者行动) | 对每个键执行给定的操作。 |
forEachKey(长并行阈值,函数变压器,耗电元件动作) | 对每个键的每个非空转换执行给定操作。 |
前景价值(长时间并行性阈值,消费者行动) | 对每个值执行给定的操作。 |
前景价值(长并行阈值,功能变压器,耗电元件动作) | 对每个值的每个非空转换执行给定操作。 |
收到(对象键) | 返回指定键映射到的值,如果此映射不包含该键的映射,则返回null。 |
getOrDefault(对象键,V默认值) | 返回指定键映射到的值,如果此映射不包含该键的映射,则返回给定的默认值。 |
hashCode() | 返回此映射的哈希代码值,即映射中每个键值对的key和。hashCode()^value。hashCode()。 |
钥匙() | 返回此表中键的枚举。 |
键集() | 返回此映射中包含的键的集合视图。 |
键集(V.价值) | 返回此映射中键的集合视图,使用给定的公共映射值进行任何添加(即Collection.add(e)和Collection)。addAll(集合))。 |
mappingCount() | 返回映射数。 |
合并(K键,V值,双功能重新映射功能) | 如果指定的键尚未与(非空)值关联,请将其与给定值关联。 |
newKeySet() | 创建一个由ConcurrentHashMap支持的从给定类型到布尔值的新集合。符合事实的 |
纽基集(容量) | 创建一个由ConcurrentHashMap支持的从给定类型到布尔值的新集合。符合事实的 |
放(K键,V值) | 将指定的键映射到此表中的指定值。 |
普塔尔(地图m) | 将指定映射中的所有映射复制到此映射。 |
putIfAbsent(K键,V值) | 如果指定的键尚未与值关联,请将其与给定值关联。 |
减少(长并行阈值,双功能变压器,双功能减速器) | 返回所有(键、值)对的给定转换的累加结果,使用给定的减数器组合值,如果没有,则返回null。 |
还原试验(长并行性阈值,双功能 |
返回使用给定的缩减器合并值累加所有项的结果,如果没有,则返回null。 |
还原试验(长并行性阈值,函数 |
返回使用给定的缩减器对所有项进行给定转换以合并值的结果,如果没有,则返回null。 |
双倍还原(long parallelism threshold,ToDoubleFunction |
返回所有项的给定转换的累加结果,使用给定的缩减器组合值,并将给定的基作为标识值。 |
还原沥青(long parallelismThreshold,ToIntFunction |
返回所有项的给定转换的累加结果,使用给定的缩减器组合值,并将给定的基作为标识值。 |
还原三斯托隆(长并行性阈值,ToLong函数 |
返回所有项的给定转换的累加结果,使用给定的缩减器组合值,并将给定的基作为标识值。 |
reduceKeys(长并行阈值,双功能减速器) | 返回使用给定减缩器组合值累加所有键的结果,如果没有,则返回null。 |
reduceKeys(长并行阈值,函数变压器,双功能减速器) | 返回使用给定的减缩器对所有键的给定转换进行累加的结果,如果没有,则返回null。 |
双倍还原(长并行阈值,ToDoubleFunction变压器,双基,双二进制运算符减速机) | 返回所有键的给定转换的累加结果,使用给定的减缩器组合值,并将给定的基作为标识值。 |
还原基斯托因(长并行阈值,ToIntFunction变压器,int基,intBinary运算符减速机) | 返回所有键的给定转换的累加结果,使用给定的减缩器组合值,并将给定的基作为标识值。 |
还原基斯托隆(长并行阈值,ToLong函数变压器,长基,长二进制运算符减速机) | 返回所有键的给定转换的累加结果,使用给定的减缩器组合值,并将给定的基作为标识值。 |
还原双(长并行阈值,ToDoubleBiFunction变压器,双基,双二进制(减速机) | 返回所有(键、值)对的给定转换的累加结果,使用给定的减数器组合值,并将给定的基作为标识值。 |
还原点(长并行阈值,ToIntBiFunction变压器,整数基,整数二进制运算符(减速机) | 返回所有(键、值)对的给定转换的累加结果,使用给定的减数器组合值,并将给定的基作为标识值。 |
还原长(长并行阈值,ToLongBiFunction变压器,长基,长二进制(减速机) | 返回所有(键、值)对的给定转换的累加结果,使用给定的减数器组合值,并将给定的基作为标识值。 |
还原值(长并行阈值,双功能减速器) | 返回使用给定的减缩器合并值累加所有值的结果,如果没有,则返回null。 |
还原值(长并行阈值,功能变压器,双功能减速器) | 返回所有值的给定转换的累加结果,使用给定的减数器组合值,如果没有,则返回null。 |
还原值加倍(长并联阈值,ToDoubleFunction变压器,双基,双二进制运算符减速机) | 返回所有值的给定转换的累加结果,使用给定的减数器组合值,并将给定的基作为标识值。 |
还原值(长并行阈值,ToIntFunction变压器,整数基,整数二进制运算符减速机) | 返回所有值的给定转换的累加结果,使用给定的减数器组合值,并将给定的基作为标识值。 |
还原值(长并行阈值,ToLong功能变压器,长基,长二进制运算符减速机) | 返回所有值的给定转换的累加结果,使用给定的减数器组合值,并将给定的基作为标识值。 |
去除(对象键) | 从此映射中删除键(及其对应的值)。 |
去除(对象键、对象值) | 仅当当前映射到给定值时,才删除键的条目。 |
代替(K键,V值) | 仅当当前映射到某个值时,才替换键的条目。 |
代替(K键,V旧值,V新值) | 仅当当前映射到给定值时,才替换键的条目。 |
搜索(长并行阈值,双功能搜索功能) | 通过对每个(键、值)应用给定的搜索函数返回非null结果,如果没有,则返回null。 |
搜索条目(长并行性阈值,函数 |
通过对每个条目应用给定的搜索函数返回非null结果,如果没有,则返回null。 |
搜索键(长并行阈值,函数搜索功能) | 通过对每个键应用给定的搜索函数返回非null结果,如果没有,则返回null。 |
搜索值(长并行阈值,功能搜索功能) | 通过对每个值应用给定的搜索函数返回非null结果,如果没有,则返回null。 |
toString() | 返回此映射的字符串表示形式。 |
价值观() | 返回此映射中包含的值的集合视图。 |
java类中声明的方法。util。抽象地图
在java接口中声明的方法。util。同时发生的ConcurrentMap
方法 |
描述 |
---|---|
弗雷奇(双消费者动作) | 对该映射中的每个条目执行给定操作,直到所有条目都已处理或该操作引发异常为止。 |
替补队员(双功能功能) | 将每个条目的值替换为对该条目调用给定函数的结果,直到处理完所有条目或函数引发异常为止。 |
必须阅读: HashMap和ConcurrentHashMap的区别
ConcurrentHashMap与Hashtable
散列表
- 哈希表 是地图数据结构的一个实现
- 这是一个遗留类,其中所有方法都使用synchronized关键字在哈希表实例上同步。
- 线程安全,因为它的方法是同步的
ConcurrentHashMap
- ConcurrentHashMap 实现映射数据结构,并提供哈希表之类的线程安全性。
- 它的工作原理是将整个哈希表数组划分为段或部分,并允许并行访问这些段。
- 在hashmap bucket级别,锁定的粒度要细得多。
- 使用 ConcurrentHashMap 当您的应用程序需要非常高的并发性时。
- 它是线程安全的,不需要同步整个地图。
- 在段级或存储桶级锁定完成写操作时,读操作可能会发生得非常快。
- 在对象级别没有锁定。
- ConcurrentHashMap不会抛出 ConcurrentModificationException 如果一个线程试图修改它,而另一个线程正在对其进行迭代。
- ConcurrentHashMap不允许空值,因此密钥在中不能为空 ConcurrentHashMap
- ConcurrentHashMap不会抛出 ConcurrentModificationException 如果一个线程试图修改它,而另一个线程正在迭代它。
属性 | 哈希表 | ConcurrentHashMap |
---|---|---|
创造 |
Map ht=new Hashtable(); |
Map chm=新的ConcurrentHashMap(); |
允许空密钥吗? |
不 |
不 |
允许空值吗? |
不 |
否(不允许空键或值) |
线程安全吗? |
对 |
是的,通过为单独的桶提供单独的锁来确保线程安全,从而提高性能。通过在没有任何阻塞的情况下同时提供读取访问,性能得到进一步提高。 |
表演 |
由于同步开销,速度较慢。 |
比哈希表更快。如果有,ConcurrentHashMap是更好的选择 读的比写的多 . |
迭代器 | Hashtable使用枚举器迭代Hashtable对象的值。哈希表键和元素方法返回的枚举不是快速失败的。 | 故障安全迭代器:ConcurrentHashMap提供的迭代器是故障安全的,这意味着它不会抛出 ConcurrentModificationException . |
结论:
如果需要线程安全的高并发实现,则建议使用 ConcurrentHashMap 代替 哈希表 .