在并发编程中,我们经常会用到容器。今天我要和你分享的话题就是:在不同场景下我们该
如何选择最优容器。
并发场景下的
Map
容器
假设我们现在要给一个电商系统设计一个简单的统计商品销量 TOP 10 的功能。常规情况
下,我们是用一个哈希表来存储商品和销量键值对,然后使用排序获得销量前十的商品。在
这里,哈希表是实现该功能的关键。那么请思考一下,如果要你设计这个功能,你会使用哪
个容器呢?
在 07 讲中,我曾详细讲过 HashMap 的实现原理,以及 HashMap 结构的各个优化细
节。我说过 HashMap 的性能优越,经常被用来存储键值对。那么这里我们可以使用
HashMap 吗?
答案是不可以,我们切忌在并发场景下使用 HashMap。因为在 JDK1.7 之前,在并发场景
下使用 HashMap 会出现死循环,从而导致 CPU 使用率居高不下,而扩容是导致死循环的
主要原因。虽然 Java 在 JDK1.8 中修复了 HashMap 扩容导致的死循环问题,但在高并发
场景下,依然会有数据丢失以及不准确的情况出现。
这时为了保证容器的线程安全,Java 实现了 Hashtable、ConcurrentHashMap 以及
ConcurrentSkipListMap 等 Map 容器。
Hashtable、ConcurrentHashMap 是基于 HashMap 实现的,对于小数据量的存取比较
有优势。
ConcurrentSkipListMap 是基于 TreeMap 的设计原理实现的,略有不同的是前者基于跳
表实现,后者基于红黑树实现,ConcurrentSkipListMap 的特点是存取平均时间复杂度是
O(log(n)),适用于大数据量存取的场景,最常见的是基于跳跃表实现的数据量比较大
的缓存。