系列文章目录
第七章 HashMsp、HashTable 和 ConcurrentHashMap 之间的区别
一、多线程环境使用哈希表
- HashMap 本身不是线程安全的。
所以,在多线程环境下使用哈希表可以使用:
HashTable 和 ConcurrentHashMap
1、HashTable
- HashTable 保证线程安全,主要就是给关键方法加上了 synchronized,是直接加到方法上的(相当于是给 this 加锁)。所以当有两个线程在操作同一个 HashTable 时就会出现锁冲突。
- 一旦触发扩容,就由该线程完成整个扩容过程。这个过程会涉及到大量的元素拷贝,效率会非常低。
2、ConcurrentHashMap
相比于 HashTable 做出了一系列的改进和优化。
- (最核心的改进)把一个全局的大锁,改进成了每个链表独立的一把小锁,这样做,大幅度降低了锁冲突的概率。
就是把每个链表的头结点作为锁对象,因为 synchronized 可以使用任意对象作为锁对象。 - 充分利用了 CAS 特性,把一些不必要加锁的环节给省略掉了。
比如:需要使用变量记录 hash 表中的元素个数。此时,就可以使用原子操作(CAS)修改元素个数。 - 还有一个激进的操作,针对读操作没有加锁。读和读之间,读和写之间都不会有锁竞争。搭配了 volatile 关键字。ConcurrentHashMap 在底层编码过程中,比较谨慎地处理了一些细节 ,修改的时候会避免使用非原子的操作。
- ConcurrentHashMap 针对扩容操作进行了单独的操作。(化整为零)
HashMap 或者 HashTable 在扩容的时候,都是需要把所有的元素都拷贝一遍(如果元素很多,拷贝就比较耗时)。
ConcurrentHashMap 一旦需要扩容,不是在一次操作中搬运完成,而是分多次来搬运,这样就可以避免单次操作过于卡顿。
总结
ConcurrentHashMap 基本的使用方法和普通的 HashMap 完全一样,只是做出了一系列的改进和优化来实现多线程环境下使用哈希表。所以,在多线程环境使用哈希表,用的是 HashTable 和 ConcurrentHashMap。