Java ConcurrentHashMap、HashTable和Synchronized Map的区别
在这里,我们将一个一个地讨论,然后在充分了解了这三者之后,再来讨论它们的区别。我们将首先讨论ConcurrentHashMap,然后是HashTable,最后是Synchronized Map。让我们先从ConcurrentHashMap开始。
ConcurrentHashMap的底层数据结构是HashTable。ConcurrentHashMap允许并发的读取和线程安全的更新操作。执行读操作的线程不需要任何锁,但执行更新操作的线程需要一个锁,但这只是Map的一个特定部分的锁(桶级锁)。而不是整个Map的并发更新是通过在内部将Map划分为一个较小的部分来实现的,这个部分由并发级别定义。默认的并发级别是16,即ConcurrentHashMap允许同时进行读和16个写(更新)操作。键值和值都不允许为空。当一个线程在迭代的时候,另一个线程可以进行更新操作,而且ConcurrentHashMap从来不会抛出ConcurrentModificationException。
语法:
ConcurrentHashMap<K,V> CHM = new ConcurrentHashMap<>();
上述构造函数创建了一个空的ConcurrentHashMap,具有
- 默认初始容量等于16
- 默认填充率等于0.75
- 默认并发级别16,其中K是键,V是ConcurrentHashMap的值
示例:
// Java program to illustrate ConcurrentHashMap
// Importing required packages
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
// Main class
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating ConcurrentHashMap class object
// Declaring object of integer an string type
ConcurrentHashMap<Integer, String> chm
= new ConcurrentHashMap<>();
// Adding entry to ConcurrentHashMap
// Custom input entries
chm.put(65, "A");
chm.put(66, "B");
// Print and display the ConcurrentHashMap
System.out.println(chm);
// Adding the entry if the given entry is not
// present in the ConcurrentHashMap Custom input
// entries
chm.putIfAbsent(67, "C");
chm.putIfAbsent(68, "D");
// Printand display the ConcurrentHashMap
System.out.println(chm);
// Removing entry With Key and Value as 68 and D
chm.remove(68, "D");
// Print and display the ConcurrentHashMap
System.out.println(chm);
// Replacing Value of an entry
chm.replace(66, "B", "E");
// Again, print and display the ConcurrentHashMap
System.out.println(chm);
}
}
输出
{65=A, 66=B}
{65=A, 66=B, 67=C, 68=D}
{65=A, 66=B, 67=C}
{65=A, 66=E, 67=C}
现在纠结于第二个概念,即。 HashTable的底层数据结构是HashTable。HashTable中的插入顺序是不保留的,它是基于键的哈希码。不允许键的重复,但值可以重复。键和值都允许有异质的对象。键和值都不允许出现null值,否则我们会得到RunTimeException,即NullPointerException。它实现了Serializable和cloneable接口,但没有实现RandomAccess。它里面的每个方法都是同步的,因此HashTable对象是线程安全的。如果我们的频繁操作是搜索操作,那么HashTable是最好的选择。
语法:
Hashtable<K,V> ht = new Hashtable<>();
上述构造函数创建了一个空的hashtable对象,初始默认容量为11,默认填充率为0.75。其中K是key,V是hashtable的值。
示例:
// Java program to illustrate HashTable
// Importing required packages
import java.io.*;
import java.util.*;
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating Hashtable object
Hashtable<Integer, String> ht = new Hashtable<>();
// Adding entry to Hashtable
// Custom input entries
ht.put(65, "A");
ht.put(66, "B");
ht.put(67, "C");
ht.put(68, "D");
// Print and display the HashTable elements
System.out.println(ht);
}
}
输出
{65=A, 68=D, 67=C, 66=B}
最后,讨论出。 在这三者之间。synchronizedMap()方法用于返回一个由指定Map支持的同步(线程安全)Map。这个方法存在于java.util.Collections.Method中。
语法:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> M)
// where M is the map to be synchronized K is key
// and V is value for the resultant synchronized map.
示例:
// Java program to demonstrate synchronizedMap() method
// Importing required packages
import java.io.*;
import java.util.*;
// Main class
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Try block to check for exceptions
try {
// Creating object of HashMap
// Declaring object of integer and string type
HashMap<Integer, String> map = new HashMap<>();
// Adding entry to map object created above
// Custom input entries
map.put(65, "A");
map.put(66, "B");
map.put(67, "C");
map.put(68, "D");
// Print and display the map object
System.out.println("Map is " + map);
// Creating a synchronized map object
// Declaring object of type integer and string
Map<Integer, String> synmap
= Collections.synchronizedMap(map);
// Print and display the synchronized map
// elements
System.out.println("Synchronized map is : "
+ synmap);
}
// Catch block to handle the exceptions
catch (IllegalArgumentException e) {
// Display the exception on the console
System.out.println(e);
}
}
}
输出
Map is {65=A, 66=B, 67=C, 68=D}
Synchronized map is : {65=A, 66=B, 67=C, 68=D}
到目前为止,我们已经讨论了足够多的概念,以及通过程序实施的内部工作。让我们最后总结一下它们之间的区别,以便紧紧抓住,了解它们之间的细微差别。
| ConcurrentHashMap | SynchronizedMap | HashTable |
| :———————————————————– | :—————————————- | :————————————– |
| 我们将获得线程安全,而不需要锁定整个Map对象,只需要用一个桶级锁。 | 我们将通过锁定整个Map对象来获得线程安全。 | 我们将通过锁定整个Map对象来获得线程安全 |
一次允许多个线程对Map对象进行安全操作。 | 在同一时间,只允许一个线程对一个Map对象进行任何操作。 | 每次允许一个线程对一个Map对象进行操作。
读取操作可以在没有锁的情况下进行,但写入操作可以用桶级锁进行。 | 每一次读和写操作都需要总Map对象 | 每一次读和写操作都需要总Map对象
当一个线程迭代Map对象时,另一个线程被允许修改Map,不会出现ConcurrentModificationException。 | 当一个线程迭代Map对象时,其他线程不允许修改Map,否则我们会得到 ConcurrentModificationException。 | 当一个线程迭代Map对象时,其他线程不允许修改Map,否则我们会得到 ConcurrentModificationException。
ConcurrentHashMap的迭代器是防故障的,不会引发ConcurrentModificationException。 | SynchronizedMap的迭代器是快速失败的,它将引发ConcurrentModificationException | HashTable的迭代器是快速失败的,它将引发ConcurrentModificationException
键和值都不允许为空。 | 键和值都允许为空 | 键和值都不允许为空。
在java 1.5版本中引入 | 在java 1.2版本中引入 | 在java 1.0版本中引入