可能會導致死迴圈和更新丟失問題。
死迴圈的成因涉及到四個方法,最初的起因是呼叫put()方法,跟著方法走一遍:
put()方法原始碼(只給出核心部分):
public v put
(k key, v value)
} modcount++
;//該key不存在,需要增加乙個結點
addentry
(hash, key, value, i)
;return null;
}
當key不存在時,呼叫addentry()方法新增新節點。方法原始碼如下:
void
addentry
(int hash, k key, v value,
int bucketindex)
resize()方法就是產生併發死鎖的原因
void
resize
(int newcapacity)
resize()方法的本質就是建立新的entry陣列,將原map中的元素重新計算位置,加入到新的map中。雖然死鎖的成因是擴充時呼叫resize()方法,但真正的產生是發生在倒數第三行的transfer()方法中。
void
transfer
(entry[
] newtable)
while
(e != null);}
}}
大體過程如下(摘自網上大神的部落格)
假設hash演算法就是簡單的用key mod entry陣列的長度。這裡一定注意e和next的指向,當併發resize()時,這兩個指標對於死鎖產生起著至關重要的作用。根據方法執**況,原map中的鍊錶元素在新的map中將順序顛倒,如上圖所示,經過一次resize()後key為7的節點排在了key為3的節點之前。
do
while
(e != null)
;
再次黏貼這段**就是強調這個do while迴圈就是產生死鎖的罪魁禍首。下面模擬死鎖產生的過程。
注意,並非所有情況下都會產生死鎖,這也需要執行緒之間的默契配合,怎麼講呢,如圖所示:
此時執行緒一,e指向key為3的節點,next指向key為7的節點。這點很重要,記下來。去執行執行緒二。
假設執行緒二正常執行,結束後的狀態如下:
此時執行緒一被喚醒,執行緒一的工作空間裡,e和next指向的元素依舊是key為3和7的節點。執行緒一開始執行。
先是執行 newtalbe[i]
= e。
然後是e = next,導致了e指向了key(7
)。而下一次迴圈的next = e.next導致了next指向了key(3
目前還沒發生問題,執行緒一接著工作。把key(7)摘下來,放到newtable[i]的第乙個,然後把e和next往下移。
e.next = newtable[i] 導致 key(3).next 指向了 key(7)。注意:此時的key(7).next 已經指向了key(3), 環形鍊錶就這樣出現了。
當產生帶環鍊錶後,如果呼叫get()方法,將會陷入死迴圈,cpu占用將達到100%。
hashmap另外乙個併發可能出現的問題是,可能產生元素丟失的現象。
考慮在多執行緒下put操作時,執行addentry(hash, key, value, i),如果有產生雜湊碰撞,
導致兩個執行緒得到同樣的bucketindex去儲存,就可能會出現覆蓋丟失的情況:
那麼如何使用執行緒安全的雜湊表結構呢,這裡列出了幾條建議:
hashtable和concurrenthashmap有什麼分別呢?它們都可以用於多執行緒的環境,但是當hashtable的大小增加到一定的時候,效能會急劇下降,因為迭代時需要被鎖定很長的時間。因為concurrenthashmap引入了分割(segmentation),不論它變得多麼大,僅僅需要鎖定map的某個部分,而其它的執行緒不需要等到迭代完成才能訪問map。簡而言之,在迭代的過程中,concurrenthashmap僅僅鎖定map的某個部分,而hashtable則會鎖定整個map。
理想情況下是 o(1)的,但是實際中會出現 hash 碰撞,導致無法達到效果。
• linkedlist 底層是基於雙向鍊錶實現的,而 arraylist 底層是基於動態陣列實現的;
• 查詢的時候 linkedlist 的效率要低於 arraylist,因為 linkedlist 需要遍歷鍊錶,而 arraylist 底層陣列根據下標直接獲取資料。
• 插入刪除資料的時候,linkedlist 效率比arraylist 效率高,因為 arraylist 在資料多的情況下會進行陣列擴容或移動陣列。
concurrenthashmap和hashtable都是支援併發的,這樣會有乙個問題,當你通過get(k)獲取對應的value時,如果獲取到的是null時,你無法判斷,它是put(k,v)的時候value為null,還是這個key從來沒有做過對映。hashmap是非併發的,可以通過contains(key)來做這個判斷。而支援併發的map在呼叫m.contains(key)和m.get(key),m可能已經不同了。
java集合面試題
分享一下面試常會問到的 集合面試題 1,arraylist,linklist,vector 的區別 arraylist 的優點 查詢速度快 使用非同步方式 linklist 增刪改速度快 vector 查詢速度快 和arraylist類似 使用同步方式 擴容是arraylist的0.5倍使用場景 a...
面試題之Java 集合
方法 size 返回集合中的項數。isempty 判斷集合中是否為空 contains object 判斷集合中是否包含某項 clear add e 從集合中新增某項 remove object 從集合中刪除某項 iterator 遍歷集合 2.1.實現iterable介面的的類可以擁有增強for迴...
Java集合的面試題
分兩大類,map和collection。而collection又有子介面list 資料儲存順序和插入順序是一樣的 set 裡面的元素具有唯一性 map是儲存鍵值對的,裡面的健不可以重複,但值可以重複 對於list主要有arraylist和linkedlist兩種實現。實現的資料結構不同,所以主要的區...