為什麼HashMap不是執行緒安全的

2021-08-27 23:26:05 字數 2538 閱讀 2023

最近因為專案的需求,經常會面試一些新人,也就會問他們一些基本的問題,例如,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...