容器类
java容器有两类框架,一类是collection,一类是map
collection接口
Map接口
object中的类
散列表 树对应的容器类
hashmap解决冲突的方法
1.再哈希 2.链表法
底层实现原理
数组+链表
哈希表
数组+链表+红黑树
技术本质
数据存储(数据结构+算法)
数组:查找时间复杂度o(1) 删除或者插入o(n)
jdk1.7 头插法
1.return h&(length-1) 作为存放的位置,length为数组的长度(2的n次方),h为hashcode,
(h=key.hashcode();)
(h先会进行右移操作,因为length-1后只有h的后四位才能影响结果,将h右移后,使得H的高位也能影响到最终结果,增加散列性。)
(实质就是把length-1后,所得二进制后四位全是1,所以最终得到的结果完全取决于hashcode的后四位,这样得到存储Index不会重复。)
2.扩容
扩容条件:map阈值&&数组中的每个位置不为孔
扩容后,进行元素转移,链表顺序会变成倒序
3.新值每次放在数组中,而旧值在新值的链表上。
4.为什么线程不安全
1、put的时候导致的多线程数据不一致。
这个问题比较好想象,比如有两个线程A和B,首先A希望插入一个key-value对到HashMap中,首先计算记录所要落到的桶的索引坐标,然后获取到该桶里面的链表头结点,此时线程A的时间片用完了,而此时线程B被调度得以执行,和线程A一样执行,只不过线程B成功将记录插到了桶里面,假设线程A插入的记录计算出来的桶索引和线程B要插入的记录计算出来的桶索引是一样的,那么当线程B成功插入之后,线程A再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程B插入的记录,这样线程B插入的记录就凭空消失了,造成了数据不一致的行为。
2、另外一个比较明显的线程不安全的问题是HashMap的get操作可能因为resize而引起死循环(cpu100%)。在元素转移时,因为链表的逆序,导致死循环。
加锁:hashtable
ConcurrentHashmap
segment []
先确定放在哪个segment,再确定具体位置
例如:16,8(并发级别)
segment[8]
jdk1.8 数组+单向链表+红黑树 尾插法
在多个节点在hash出现碰撞时,存储在1个链表中,那么要查找某一个节点,就会花费o(n)时间
数组默认大小为16,最大值2的30次7方,
扩容:负载因子=0.75,数组容量=16*0.75
阈值:链表长度过长时,将链表变成红黑树,减少查询深度
阈值2:小于这个值,再变成链表
concurrentHashMap的实现 采用的什么锁
linkedhashmap treemap
arraylist:底层是数组
linkedlist:底层是双向链表
copyonwirtearraylist