标签:this aci 手动 hash 提取 play 表示 提高效率 边界值
ConcurrentMap及其子类是JDK1.5提供的一套用于应对高并发的映射机制,在高并发时能比较好地保证线程安全。
性质(其下前4点同HashMap的性质)
底层基于数组+链表的结构实现
数组的默认容量16(表示有16个桶)
默认加载因子:0.75
默认扩容方法:增加一倍的桶容量(13个桶的时候开始扩容,12只是个边界值,非扩容点)
若给定初始值,则会在底层有以下判断(源码)
其中MAXIMUM_CAPACITY
=230 可以看出,ConcurrentHashMap最多允许存在230个桶。
若初始值 >=230-1 则给最大容量,否则按运算规则计算真实容量。经计算,若初始值给19,则实际容量为32 ;若初始值给48则实际容量为128。理论上可证,给出任意一个初始值,其真实大小一定是2的n次方。进一步可以发现:
注意:向下取整
与ConcurrentHashMap不同,HashMap直接拿值进入tableSizeFor
计算,有兴趣可以看看源码。
?? 问:若给定初始容量为100,在极端情况下,ConcurrentHashMap需不需要扩容?HashMap需不需要扩容?
【注】极端条件:元素都放在桶里
=> 不需要扩容
=> 需要扩容
在JDK1.8中,为了提高效率引入了红黑树机制,当桶中的元素个数超过8时,这个桶的链表扭转成一颗红黑树。如果红黑树的节点个数不足7个时,红黑树扭转回链表。
??红黑树(本质上是一棵自平衡二叉查找树)
树:一种数据结构,每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树;
二叉树:每个结点最多只能有两棵子树,且有左右之分
二叉查找树(二叉排序树):
1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2. 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3. 左、右子树也分别为二叉排序树;
4. 没有键值相等的结点。
平衡二叉查找树:叶节点高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。(平衡的特点)
红黑树(自平衡二叉树):
红黑树在构建过程中,每次添加一个新的节点都需要考虑是否需要修正:
时间复杂度:Olog(n)
异步线程安全
HashMap-异步线程不安全。因为没有锁,可能发生两个线程操作同一个链。
Hashtable-对外提供的所有方法都加了锁(除了构造方法),锁对象是this。因此,其会把整个映射都锁起来,虽然线程安全了,但是只能同步访问,效率低下。
ConcurrentHashMap-采用了分段(桶)锁机制,在后序版本中,ConcurrentHashMap在分段锁基础上引入了读写锁机制:
CAS-ConcurrentHashMap利用锁保证线程安全,但是在使用锁的时候,造成CPU的资源浪费(例如线程调度,线程上下文切换等)在JDK1.8中,考虑到锁带来的开销,引入了无锁算法CAS(Compare And Swp)
官方解释:我认为V的值应该是A,如果是,那么将V的值更新为B,否则不修改并告诉V的实际值是多少。
其中:V代表内存值,A代表旧的预期值,B代表新的预期值。
其目的在于判断欲修改的值是否被修改过。
CAS的过程一旦被打断,就会重新开始。以确保操作的原子性。
因为CAS涉及到线程的重新调度问题,所以需要结合具体的cpu内核架构来涉及,因此Java的CAS底层是依靠C语言实现的。目前市面上,服务器流行的内核架构都是支持CAS。
提供了用于截取子映射的方法
ConcurrentNavigableMap是一个接口,一般使用的是它的实现类:ConcurrentSkipListMap:并发跳跃映射表。底层基于跳跃表实现。
跳跃表:
几个方法和性值
标签:this aci 手动 hash 提取 play 表示 提高效率 边界值
原文地址:https://www.cnblogs.com/juzhuxiaozhu/p/13154215.html