java集合知识整理及部分源码分析

0、HashMap底层数组+链表+红黑树
HashTable底层数组+链表实现

1、HashMap key 和value 都可以为空 
HsahTable都不可以回报空指针异常

2、HashMap 继承AbstractMap   , 
HashTable继承Dictionary   
都实现 Map接口  extends implements

3、HashMap线程不安全  
HashTable线程安全 效率低

4、HashTabel初始size为11,扩容newsize = oldsize*2+1
     HashMap初始size为16,扩容 newsize = oldsize*2,size一定为2的n次幂

5、HashTable计算index的方法:index=(hash&0x7FFFFFFF)%tab.length
    HashMap计算index方法 index = hash & (tab.length -1)


6、HashMap的resize()方法
①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容;
②.每次扩展的时候,都是扩展2倍;
③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。

7、HashMap的putVal()方法

8、hashMap插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)

9、HashMap和Hashtable都是用hash算法来决定其元素的存储,因此HashMap和Hashtable的hash表包含如下属性:


容量(capacity):hash表中桶的数量
初始化容量(initial capacity):创建hash表时桶的数量,HashMap允许在构造器中指定初始化容量
尺寸(size):当前hash表中记录的数量
负载因子(load factor):负载因子等于“size/capacity”。负载因子为0,表示空的hash表,0.5表示半满的散列表,
依此类推。轻负载的散列表具有冲突少、适宜插入与查询的特点(但是使用Iterator迭代元素时比较慢)

10、ConcurrentHashMap

1、底层采用分段的数组+链表实现,线程安全

2、通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,
默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。

3、Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,
ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术

4、有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,
这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁

5、扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容)
插入前检测需不需要扩容,有效避免无效扩容

6、ConcurrentHashMap是使用了锁分段技术来保证线程安全的。

ConcurrentHashMap是JDK1.5添加的新的集合,用来保证线程安全性,提高Map集合的并发效率
ConcurrentHashMap使用了Segment的概念,莫若友16各Segment
Segment里面依然还是数字+链表的数据结构,相当于给HashMap分桶处理了
因每次只会锁住其中一个Segment,所有性能非常好
然而,有意思的是,随着 JDK 1.8 中对 HashMap 的改进,同时又对 ConcurrentHashMap 进行了改进,
抛弃了 Segment + 数组 + 单向链表 的设计,改为了和 HashMap 同样的 数组 + 单向链表 + 红黑树 的数据结构。

同时,ConcurrentHashMap 使用了 CAS 算法 + Synchronized 来保证集合的线程安全性,
ConcurrentHashMap 相当于一个性能安全的 HashMap。

猜你喜欢

转载自blog.csdn.net/weixin_39650971/article/details/89225761