HashTable和ConcurrentHashMap的区别

目录

HashMap

HashTable

ConcurrentHashMap

ConcurrentHashMap在其他方面的改进

采用CAS机制

优化了扩容机制


HashMap

多线程环境中使用哈希表

HashMap不适合在多线程环境下使用,HashMap无法保证线程安全。因此不支持并发访问。在多线程下使用哈希表可以使用HashTable或者ConcurrentHashMap。

但是更推荐使用concurrentHashMap。

HashTable

hashTable底层也是基于哈希表实现的,HashTable是线程安全的,内部使用synchronized关键字加锁。相当于给this加锁。

给关键方法加上锁之后,虽然保证了在多线程环境下的使用不会出现线程安全问题,但是HashTable加锁的粒度太粗了。

hashTable是针对整个哈希表进行加锁的,任何增删改查的操作都是触发加锁,也就可能有锁竞争。

加锁的粒度不同,引发线程对锁的竞争就越高。

如果多个线程对同时需要操作HashTable的一个方法,那么此时就会有锁竞争,但是最终只能有一个线程获取锁对象。那么其他线程此时就只能阻塞等待了,当释放锁之后,剩余线程继续进行锁竞争和阻塞。

如果此时线程1给数组的0下标进行插入元素,线程2给数组的1下标进行插入元素,此时是不会出现线程安全的问题的,但是我们的HashTable的加锁机制是给整个哈希表进行加锁操作的。是针对this进行加锁的,所以此时就会有一个线程阻塞等待。这就导致了hashTable的效率非常的低。

ConcurrentHashMap

由于HashTable在多线程环境下表现并不是很出色,效率非常低。于是就出现了ConcurrentHashMap。

上述的HashTable是整个哈希表只有一把锁,这也就导致了效率的低下。但是ConcurrentHashMap

不是只要一把锁,而是一个链表的头结点有一把锁。

也就说只有是针对不同链表的进行操作,就不会出现锁竞争,也就不会阻塞等待。

这就导致大部分操作都是没有阻塞的。

上述情况是jdk1.8开始的。实际在1.8之前的时候,是采用分段锁的方式来实现加锁的,和上述情况相似,是采用好几个链表共用一把锁对象。

ConcurrentHashMap在其他方面的改进

采用CAS机制

比如一下获取元素个数/更新元素个数的操作就可以使用CAS了,也没有必要加锁。

CAS也能保证线程安全,而且比锁更高效。

优化了扩容机制

hashtable的扩容是当达到一定的负载因子的时候,扩容就需要重新申请空间,然后把旧的空间上的元素全部挪动到新的空间中。

如果元素要是非常多,此时的扩容就会非常的卡顿。

concurrentHashMap的扩容是采用化整为0的策略,不会视图一次将全部元素都诺过去,而是只挪动一小部分。

此时就有两个hash表了。

当删除元素的时候,就会查询要删除的元素在那个表,然后删除。

当添加元素的时候,就直接插入在新表中。

每次操作都会触发挪动,每次也都是挪动一小部分。

最终会将整个表都全部挪过去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值