目录
1. Colection
1.1 List
1.1.1 ArrayList
int newCapacity = oldCapacity + (oldCapacity >> 1);
1.1.2 Vector
int newCapacity = oldCapacity * 2;
1.1.2 LinkedList
1.2 Set
1.2.1 HashSet
1.2.2 TreeSet
1.2.3 LinkedHshSet
2 Map
2.1 HashMap
2.1.1 java 7
2.1.2 java 8
1、put(key, value)中直接调用了内部的putVal方法,并且先对key进行了hash操作;
2、putVal方法中,先检查HashMap数据结构中的索引数组表是否位空,如果是的话则进行一次resize操作;
3、以HashMap索引数组表的长度减一与key的hash值进行与运算,得出在数组中的索引,如果索引指定的位置值为空,则新建一个k-v的新节点;
4、如果不满足的3的条件,则说明索引指定的数组位置的已经存在内容,这个时候称之碰撞出现;
5、在上面判断流程走完之后,计算HashMap全局的modCount值,以便对外部并发的迭代操作提供修改的Fail-fast判断提供依据,于此同时增加map中的记录数,并判断记录数是否触及容量扩充的阈值,触及则进行一轮resize操作;
6、在步骤4中出现碰撞情况时,从步骤7开始展开新一轮逻辑判断和处理;
7、判断key索引到的节点(暂且称作被碰撞节点)的hash、key是否和当前待插入节点(新节点)的一致,如果是一致的话,则先保存记录下该节点;如果新旧节点的内容不一致时,则再看被碰撞节点是否是树(TreeNode)类型,如果是树类型的话,则按照树的操作去追加新节点内容;如果被碰撞节点不是树类型,则说明当前发生的碰撞在链表中(此时链表尚未转为红黑树),此时进入一轮循环处理逻辑中;
8、循环中,先判断被碰撞节点的后继节点是否为空,为空则将新节点作为后继节点,作为后继节点之后并判断当前链表长度是否超过最大允许链表长度8,如果大于的话,需要进行一轮是否转树的操作;如果在一开始后继节点不为空,则先判断后继节点是否与新节点相同,相同的话就记录并跳出循环;如果两个条件判断都满足则继续循环,直至进入某一个条件判断然后跳出循环;
9、步骤8中转树的操作treeifyBin,如果map的索引表为空或者当前索引表长度还小于64(最大转红黑树的索引数组表长度),那么进行resize操作就行了;否则,如果被碰撞节点不为空,那么就顺着被碰撞节点这条树往后新增该新节点;
10、最后,回到那个被记住的被碰撞节点,如果它不为空,默认情况下,新节点的值将会替换被碰撞节点的值,同时返回被碰撞节点的值(V)。
1、在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失;
2、在jdk1.8中,在多线程环境下,会发生数据覆盖的情况。
2.2 ConcurrentHashMap
2.2.1 java 7
2.2.2 java 8
1、计算hashcode;
2、table为空,则执行初始化,默认长度16;(基于CAS)
3、否则,计算hashcode在数组中对应的下标,并获取下标对应的头结点;
4、头结点为空,添加头结点;(基于CAS)
5、头结点不为空,但头结点值为 MOVED ,表示正在扩容,帮助其扩容线程扩容(基于CAS)
6、否则,头结点不为空,且未处于扩容状态,尝试添加新结点(基于Synchronized)
7、判断当前桶内节点数量是否大于阈值,大于则扩容 (基于CAS)
参考:
[2] HashMap线程不安全的体现
原文:https://www.cnblogs.com/moxie-/p/13292310.html