1.HashMap
在多线程环境下,HashMap是线程不安全的
2.HashTable
在多线程下是安全的,但是hashtable是给各种方法加synchronized,相当于对this加锁,是针对哈希表对象来加锁,一个哈希表,只有一个锁。在多线程下,无论这些线程如何操作哈希表,都会产生锁冲突,性能极低,不推荐使用。
3.ConcurrentHashMap
1.锁粒度的控制
ConcurrentHashMap里面的每个哈希桶加锁,只有两个线程访问同一个哈希桶才有锁竞争,并且哈希桶的个数非常多,所以大大降低了锁冲突的概率,提高了性能。
2.只给写加锁
只有在两个线程同时修改的时候才有锁冲突,而我们大部分操作是读操作,也提高了性能。
但是如果一个线程读,一个线程写,只对写操作加锁,不会产生锁冲突,可能会出现读的结果是一个修改一半的数据,线程不安全。
所以在设计的时候考虑到这一点保证读的时候是要么是修改前的版本,要么是修改后的版本。
并且在读操作中大量使用vilatile来保证数据是可靠的,及时的。
3.充分利用CAS特性
因为CAS是线程安全的,可以利用CAS维护元素个数,实现一些轻量级锁。
4.优化扩容方式
普通的扩容方式是申请一个更大的空间,把旧的数据搬运到新的数组上。但是当数据特别大的时候,搬运的开销会很大,可能会卡很久。
而ConcurrentHashMap在扩容的时候,不是一次性完成搬运。
扩容的时候,新老数组会同时存在一段时间,每次进行哈希表的操作,都会把旧的内存上的元素搬运一部分到新空间上,直到搬运完成,再释放旧的空间。
在这个过程查询元素,新旧数组都搜索。要插入元素,直接插入新数组上。要删除元素,直接在老数组上删除。