
底层数组+链表完结,不管key仍是value都不能为null,线程安全,完结线程安全的办法是在修正数据时锁住整个HashTable,功率低,ConcurrentHashMap做了相关优化
核算index的办法:index = (hash & 0x7FFFFFFF) % tab.length
ConcurrentHashMap
底层选用分段的数组+链表完结,线程安全
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap答应多个修正操作并发进行,其关键在于运用了锁别离技能
A8站源码交易平台
在存储结构中ConcurrentHashMap比HashMap多出了一个类Segment,而Segment是一个可重入锁。
锁分段技能:首要将数据分红一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁拜访其间一个段数据的时分,其他段的数据也能被其他线程拜访。
ConcurrentHashMap默许将hash表分为16个桶,比如get、put、remove等常用操作只锁住当时需求用到的桶。这样,本来只能一个线程进入,现在却能一起有16个写线程履行,并发功能的提高是清楚明了的。
A8站源码交易平台
经过不加锁和加锁两种计划操控跨段操作的的安全性。
A8站源码交易平台
默许容量不同,扩容不同
功率不同:HashTable 要慢,因为加锁
咱们知道 Hashtable 是 synchronized 的,可是 ConcurrentHashMap 同步功能更好,因为它只是依据同步级别对 map 的一部分进行上锁
它们都能够用于多线程的环境,可是当 Hashtable 的巨细添加到必定的时分,功能会急剧下降,因为迭代时需求被确认很长的时刻。因为 ConcurrentHashMap 引入了切割(segmentation),不管它变得多么大,只是需求确认 Map 的某个部分,其它的线程不需求比及迭代完结才干拜访 Map。简而言之,在迭代的进程中,ConcurrentHashMap 只是确认 Map 的某个部分,而 Hashtable 则会确认整个 Map
CocurrentHashMap 是由 Segment 数组和 HashEntry 数组和链表组成
中心数据如 value,以及链表都是 volatile 润饰的,确保了获取时的可见性
将当时 Segment 中的 table 经过 key 的 hashcode 定位到 HashEntry。
不为空则需求新建一个 HashEntry 并加入到 Segment 中,一起会先判别是否需求扩容
尽管 HashEntry 中的 value 是用 volatile 关键词润饰的,可是并不能确保并发的原子性,所以 put 操作时依然需求加锁处理
测验自旋获取锁
CocurrentHashMap(JDK 1.8)
最大特点是引入了 CAS
A8站源码交易平台
对 sizeCtl 的操控都是用 CAS 来完结的:
N 表明有 -N-1 个线程正在进行扩容操作
假如 table 初始化完结,表明table的容量,默许是table巨细的0.75倍,用这个公式算 0.75(n – (n >>> 2))
处理:对变量添加一个版本号,每次修正,版本号加 1,比较的时分比较版本号。
依据 key 核算出 hashcode
经过 key 定位出的 Node,假如为空表明当时方位能够写入数据,运用 CAS 测验写入,失利则自旋确保成功
假如都不满意,则运用 synchronized 锁写入数据
get 进程
假如是红黑树那就依照树的办法获取值
A8站源码交易平台