线程安全的Map经常在Java面试被问到,线程安全的Map主要有5大类,下面详解5大线程安全Map@mikechen
1.ConcurrentHashMap
ConcurrentHashMap是Java中最常用的线程安全的Map实现之一。
在JDK1.7中ConcurrentHashMap采用了数组+Segment+分段锁的方式实现。
如下图所示:
JDK8中ConcurrentHashMap参考了JDK8 HashMap的实现,进行全面升级。
如下图所示:
示例如下:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); // 使用ConcurrentHashMap的forEach方法遍历Map map.forEach((key, value) -> { System.out.println(key + ": " + value); });
ConcurrentHashMap支持高并发读写操作,可以实现高效的并发处理。
想更加深入的了解ConcurrentHashMap,请查看:ConcurrentHashMap详解(作用原理及使用场景)
2.Hashtable
Hashtable是Java中最早提供的线程安全的Map实现,如下所示:
Hashtable<String, Integer> table = new Hashtable<>(); table.put("apple", 1); table.put("banana", 2); table.put("orange", 3); // 使用Hashtable的forEach方法遍历Map table.forEach((key, value) -> { System.out.println(key + ": " + value); });
Hashtable对数据的读写操作,都采用Synchronized来实现线程安全,如下所示:
public synchronized V get(Object key) { Entry<?,?> tab[] = table; ...... }
在多线程环境下,无论是读数据,还是修改数据,在同一时刻只能有一个线程在执行synchronize方法,因为是对整个表进行锁定。
所以Hashtable性能比较差,现在都建议使用ConcurrentHashMap来替换。
3.ConcurrentSkipListMap
ConcurrentSkipListMap是一种基于跳表(Skip List)实现的线程安全的Map。
跳表是一种可以支持快速查找、插入、删除的数据结构,与红黑树相比,它的查询效率更高。
ConcurrentSkipListMap支持高并发读写操作,同时也支持高级操作,比如原子性的putIfAbsent、replace等操作。
如下所示:
ConcurrentSkipListMap<String, Integer> map = new ConcurrentSkipListMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); // 使用ConcurrentSkipListMap的forEach方法遍历Map map.forEach((key, value) -> { System.out.println(key + ": " + value); }); // 使用ConcurrentSkipListMap的putIfAbsent方法插入新值 map.putIfAbsent("peach", 4); // 使用ConcurrentSkipListMap的replace方法替换值 map.replace("banana", 5); // 使用ConcurrentSkipListMap的get方法获取值 int value = map.get("apple");
4.SynchronizedMap
SynchronizedMap是一种基于Synchronized关键字实现的线程安全的Map。
如下所示:
Map<String, Integer> map = new HashMap<>(); Map<String, Integer> synchronizedMap = Collections.synchronizedMap(map); synchronizedMap.put("apple", 1); synchronizedMap.put("banana", 2); synchronizedMap.put("orange", 3); // 使用SynchronizedMap的forEach方法遍历Map synchronizedMap.forEach((key, value) -> { System.out.println(key + ": " + value); });
它通过Synchronized对整个Map对象进行同步来实现并发安全,因此它的性能比ConcurrentHashMap和ConcurrentSkipListMap要差一些。
SynchronizedMap的优点是实现简单,易于使用,可以作为一种基础的线程安全Map使用。
5.ConcurrentHashMap.KeySetView
ConcurrentHashMap.KeySetView是ConcurrentHashMap中的一个内部类,它提供了一种只读的线程安全的Set视图,可以用于读取ConcurrentHashMap中的Key。
如下所示:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); ConcurrentHashMap.KeySetView<String, Integer> keySetView = map.keySet(); // 使用ConcurrentHashMap.KeySetView的forEach方法遍历Map的Key keySetView.forEach(key -> { System.out.println(key); });
ConcurrentHashMap.KeySetView支持高并发读操作,但不支持写操作,因此它适用于读多写少的场景。
以上就是线程安全的Map详解,更多线程安全集合,请查看:线程安全的集合有哪些(5类线程安全集合)
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》