序
最近因為專案的需求,經常會面試一些新人,也就會問他們一些基本的問題,例如,hashmap和hashtable的區別是什麼,一般人想到的就是hashmap不是執行緒安全,這點我想幾乎來面試的人都知道,但是再深入問下為什麼hashmap不是執行緒安全的,幾乎沒有人答上來,當然了,我也不會因為你回答不上來就認為能力不行,只能認為是這個題目是一道附加題,大家都懂得,下面我們就簡單看下為什麼hashmap不是執行緒安全的。
正文
例如我有幾個執行緒同時給裡面放入元素,key為執行緒的名字,value為乙個物件,也可以是乙個list,暫且不管,好了,現在我們一起看源**吧。
public v put(k key, v value)
if (key == null)
return putfornullkey(value);
//此時的hash值是根據傳入的key值進行hash得到的,儘管有些人認為執行緒的名字命名的好的話就不會有hash相同的情況,即使如此也是有可能的,這裡我們就假如hash的結果是相同的
int hash = hash(key);
int i = indexfor(hash, table.length);//此時的i也是相同的。
for (entrye = table[i]; e != null; e = e.next)
}modcount++;
addentry(hash, key, value, i);//跟進去看下
return null;
}
進入addentry方法
void addentry(int hash, k key, v value, int bucketindex)
//假設都是第一次進入這個方法的,那麼此時table陣列應該是空的。
createentry(hash, key, value, bucketindex);
}
進入createentry方法
void createentry(int hash, k key, v value, int bucketindex)
同樣的,在addentry方法中的如果判斷容量超過了限制,就會擴容,此時resize也是會有問題的
void resize(int newcapacity)
entry newtable = new entry[newcapacity];
transfer(newtable, inithashseedasneeded(newcapacity));
table = newtable;
threshold = (int)math.min(newcapacity * loadfactor, maximum_capacity + 1);
}
刪除乙個元素呢?其實在某種場景下也是會有問題的。
final entryremoveentryforkey(object key)
int hash = (key == null) ? 0 : hash(key);
int i = indexfor(hash, table.length);
//(1)
entryprev = table[i];
entrye = prev;
while (e != null)
prev = e;
e = next;
}return e;
}
在(1)處時,根據i獲取了對應陣列的鍊錶的頭部,然後在(2)處進行把鍊錶的頭部指定為當前頭部的下乙個元素,如果此時恰巧有另外乙個執行緒在此處放入了乙個元素,雖然機率不大,但是總有可能發生,因此還是執行緒不安全的。
再看下hashtable的原始碼:
public synchronized v put(k key, v value)
// makes sure the key is not already in the hashtable.
entry tab = table;
int hash = hash(key);
int index = (hash & 0x7fffffff) % tab.length;
for (entrye = tab[index] ; e != null ; e = e.next)
}
public synchronized v remove(object key) else
count--;
v oldvalue = e.value;
e.value = null;
return oldvalue;}}
return null;
}
public synchronized v get(object key)
}return null;
}
全部都同步了,因此敢說hashtable是執行緒安全的。 hashMap在put值的時候為什麼不是執行緒安全的
上面的是hashmap的儲存資料結構,通過給map的key計算hash值,然後決定value放到陣列的對應索引位置上,這樣就可以通過計算key的hash值,直接去陣列中拿到value 所以hashmap是o 1 的複雜度 當key衝突 不同的key生成的hash值是 相同的 的時候,就需要把多個va...
HashMap為什麼是執行緒不安全的
hashmap底層是乙個entry陣列,當發生hash衝突的時候,hashmap是採用鍊錶的方式來解決的,在對應的陣列位置存放鍊錶的頭結點。對鍊錶而言,新加入的節點會從頭結點加入。我們來分析一下多執行緒訪問 1.在hashmap做put操作的時候會呼叫下面方法 新增entry。將 key value...
HashMap為什麼是執行緒不安全的
jdk1.7中hashmap的transfer函式如下 void transfer entry newtable,boolean rehash int i indexfor e.hash,newcapacity e.next newtable i newtable i e e next 此函式tra...