多线程下使用哈希表
(1)HashMap 线程不安全(不建议使用)
(2)Hashtable 线程安全(不建议使用)
(3)ConcurrentHashMap 线程安全(建议使用)
🔎Hashtable
Hashtable 只是简单的把关键方法加上了锁
如图
这相当于对Hashtable本身加锁
无论做什么都需要加锁
🔎ConcurrentHashMap
注意
ConcurrentHashMap 是JDK1.8引入的
ConcurrentHashMap 仍然是使用 synchronized 进行加锁
但不是锁住整个对象
而是用每个链表的头节点作为锁的对象
🔎区别
(1)加锁粒度不同
对于 Hashtable, 直接为整个哈希表加锁🥝
当多个线程插入多个不同的元素(多线程修改多个不同的变量)
线程1在下标1位置上插入元素
线程2在下标2位置上插入元素
这种操作不会引起线程安全问题, 但由于对整个哈希表都加了锁, 所以也会产生锁冲突
对于 ConcurrentHashMap, 将每个链表的头节点作为一把锁🥝
当多个线程插入多个不同的元素(多线程修改多个不同的变量)
线程1在下标1位置上插入元素
线程2在下标2位置上插入元素
由于将每个链表的头节点作为一把锁, 所以这种情况下不会产生锁冲突
(2)利用了CAS
对于 Hashtable🥝
size 属性通过 synchronized 操作更新(较慢)
对于 ConcurrentHashMap🥝
size 属性通过 CAS 更新(较快)
(3)扩容策略的调整
对于 Hashtable🥝
一旦触发扩容给操作, 就需要持有锁的线程完成整个扩容过程(将旧的元素搬运到新的内存空间, 搬运完毕将旧的内存空间释放), 该过程涉及到大量的元素拷贝, 效率较低
对于 ConcurrentHashMap🥝
化整为零
扩容操作不会一次性将所有元素全部搬运,而是只搬运一小部分
扩容时, 新旧空间同时存在
后续的线程也会执行上述操作, 直到将所有元素全部搬运完毕
由于每次只需要拷贝少量元素, 效率较高
(在扩容期间)
插入元素会插入在新开辟的内存空间
查找元素会同时查找新旧两块空间
删除元素会同时查找新旧两块空间,在哪块空间就删除哪块空间的元素
🔎结尾
创作不易,如果对您有帮助,希望您能点个免费的赞👍
大家有什么不太理解的,可以私信或者评论区留言,一起加油