HashMap多線程put后get為null和多線程put的時候可能導致元素丟失


一、多線程put后get為null 

  源碼定位

 1 void  transfer(Entry[] newTable) {
 2      Entry[] src = table;
 3      int  newCapacity = newTable.length;
 4      for  ( int  j =  0 ; j < src.length; j++) {
 5          Entry e = src[j];
 6          if  (e !=  null ) {
 7              src[j] =  null ;//將table[j]設置為null,並發訪問到 原table返回的就是null
 8              do  {
 9                  Entry next = e.next;
10                  int  i = indexFor(e.hash, newCapacity);
11                  e.next = newTable[i];
12                  newTable[i] = e;
13                  e = next;
14              }  while  (e !=  null );
15          }
16      }
17 }

  分析:線程1將src[j] = null;即將table[j] = null;因為代碼第二行定義了Entry[] src = table;即src和table是對同一對象的引用。

  這時切換到線程2,線程2此時若正在調用get(key)方法:

 1 public V get(Object key) {  
 2 
 3         if (key == null)  
 4 
 5             return getForNullKey();  
 6 
 7         int hash = hash(key.hashCode());  
 8 
 9         // indexFor方法取得key在table數組中的索引,table數組中的元素是一個鏈表結構,遍歷鏈表,取得對應key的value  
10 
11         for (Entry e = table[indexFor(hash, table.length)]; e != null; e = e.next) {  
12 
13             Object k;  
14 
15             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
16 
17                 return e.value;  
18 
19         }  
20 
21         return null; 
22 }

  若get(key)中key經hash和indexFor()計算后正好落到table[j]上,則此時取到的Entry為null(第11行),直接跳出for循環,來到第21行,return null,違反了錯覺。

 

二、多線程put的時候可能導致元素丟失

  源碼定位

1 void  addEntry( int  hash, K key, V value,  int  bucketIndex)
2 {
3      Entry<K,V> e = table[bucketIndex];
4      table[bucketIndex] =  new  Entry<K,V>(hash, key, value, e);//這里線程1和線程2同時獲取e,執行后必然有一個丟失
5      if  (size++ >= threshold)
6          resize( 2  * table.length);
7 }

 

  問題出在第4行table[bucketIndex] = new Entry<K,V>(hash,key,value,e);如果兩個線程同時都取得了e,則他們下一個元素都是e,然后賦值給table元素的時候有一個成功有一個丟失(先賦值的丟失)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM