首先HashTable和ConcurrentHashMap都是线程安全的哈希表,我们知道在JDK1.8之后哈希表的底层是数组 + 链表,在数组长度大于等于64且链表长度大于等于8的时候链表会变成红黑树,增加我们的查询效率,但是HashMap是线程不安全的集合类,当我们有多个线程进行修改同一个变量的时候,会造成实际结果和预期结果不服的现象,如果我们要保证我们的线程安全,我们可以使用线程安全的哈希表进行操作,这时候我们Java中提供了两种线程安全的哈希表,HashTable和ConcurrentHashMap。
HashTable:HashTable是线程安全的哈希表,但是我们观察底层源码会发现,HashTable保证线程安全无非就是给每个方法都用synchronized关键字进行加锁,这样我们的整个哈希表只有一把锁,当我们有十个线程竞争锁的时候,只要有一个线程的到锁,其他九个线程就需要阻塞等待,这会导致整个效率比较低效。所以我们使用ConcurrentHashMap这样的线程安全的哈希表更好。
ConcurrentHashMap:
优点1:在JDK1.7的时候,我们的ConcurrentHashMap使用叫分段锁的概念来对哈希表保证线程线程安全,相较于HashTable的一个哈希表只有一个锁来说,ConcurrentHashMap中有多个锁,我们把整个哈希表分为几段,每一段都有一个锁,就降低了我们锁冲突的一个概率。在JDK1.8之后每个哈希桶都配有一把锁,而且当我们计算的hashCode不相同的时候,不会触发锁冲突,把锁的粒度变得更小了。
优点2:ConcurrentHashMap对读操作不加锁,只对写操作进行加锁。
优点3:ConcurrentHashMap更好的利用了我们的CAS机制,比如我们获取ConcurrentHashMap中的size属性,就是通过我们的CAS,来避免出现重量级锁的情况
优点4:优化了扩容问题,发现需要扩容的线程,ConcurrentHashMap会创建一个新的数组,同时只是搬移几个元素过去,不是copy一个数组。扩容期间,我们的新老数组共同存在,每一次对ConcurrentHashMap进行操作,就从老数组搬移一些元素到新数组,等到搬完之后,在释放掉老数组,这样就提高了我们的效率。