序言
沒有bug的程序猿并不是好程序员,是否这一大道理。
如果没有bug,哪来的发展室内空间;
如果没有bug,哪来的维护费;
如果没有bug,哪来的程序流程升級;
......
就算是大家每天用的高手们写的java最底层都是会有系统漏洞,更何况大家这种小人物呢。
程序猿们,在jdk1.7中HashMap有一个严重错误-循环链表,大家知道吗?
jdk1.7 HashMap框架图
jdk1.7是数组 链表的构造
jdk1.7版本号中关键存有2个难题
线程同步另外put时,假如另外启用了resize实际操作,很有可能会造成 循环链表造成,从而促使后边get的情况下,会无限循环。下边详尽论述循环链表怎样产生的。
resize函数
数组扩充函数,关键的作用便是建立扩充后的新数组,而且将启用transfer函数将旧数组中的原素转移到新的数组
void resize(int newCapacity)
{
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
......
//建立一个新的Hash Table
Entry[] newTable = new Entry[newCapacity];
//将Old Hash Table上的数据备份转移到New Hash Table上
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
transfer函数
transfer逻辑性实际上也简易,解析xml旧数组,将旧数组原素根据头插法的方法,转移到新数组的相匹配部位难题出就出在头插法。
void transfer(Entry[] newTable)
{
//src旧数组
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j ) {
Entry<K,V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);//因为是链表,因此 有一个循环系统全过程
}
}
}
static int indexFor(int h, int length){
return h&(length-1);
}
下边举个具体事例
//下边详尽表述必须采用这些编码,因此 先型号,将一下编码分成五个流程
do {
1、Entry<K,V> next = e.next;
2、int i = indexFor(e.hash, newCapacity);
3、e.next = newTab[i];
4、newTable[i] = e;
5、e= next;
} while(e != null)
刚开始HashMapHashMapHashMap容积设成2,载入阀值为2∗0.75=12*0.75=12∗0.75=1
进程T2 和进程T1另外插进原素,因为阀值为1,因此 都必须启用resize函数,开展扩充实际操作
进程T1先堵塞于编码Entry<K,V> next = e.next;,以后进程T2 实行完扩充实际操作
以后进程T1被唤起,执行,进行一次循环系统后
刚开始e→3,next→7, 实行下边编码后,e→7, next→3
2、int i = indexFor(e.hash, newCapacity);
3、e.next = newTab[i];
4、newTable[i] = e;
5、e= next;
1、Entry<K,V> next = e.next;
进程 T1 实行第二次循环系统后
刚开始e→7,next→3, 实行下边编码后,e→3, next→null
2、int i = indexFor(e.hash, newCapacity);
3、e.next = newTab[i];
4、newTable[i] = e;
5、e= next;
1、Entry<K,V> next = e.next;
进程T1实行第三次循环系统后,产生无限循环
刚开始e→3,next→null, 实行下边编码后,e→null
2、int i = indexFor(e.hash, newCapacity);
3、e.next = newTab[i];
4、newTable[i] = e;
5、e= next;
1、Entry<K,V> next = e.next;
倘若你实行get(11), 11%4=3, 深陷无限循环
这个问题只存有于JDK1.7中,在JDK1.8中应用了不一样的扩充完成方法,促使不容易出現这类状况。
HashMap 则应用了拉锁式的散列优化算法,在 JDK 1.8 中导入了红黑树提升太长的链表。
算法设计平面图以下: