HashMap线程不安全的原因和解决方案
1、HashMap線程不安全原因:
JDK1.8 中,由于多線程對HashMap進行put操作,調用了HashMap#putVal(),具體原因:假設兩個線程A、B都在進行put操作,并且hash函數計算出的插入下標是相同的,當線程A執行完第六行代碼后由于時間片耗盡導致被掛起,而線程B得到時間片后在該下標處插入了元素,完成了正常的插入,然后線程A獲得時間片,由于之前已經進行了hash碰撞的判斷,所有此時不會再進行判斷,而是直接進行插入,這就導致了線程B插入的數據被線程A覆蓋了,從而線程不安全!!!
JDK1.8 HashMap線程不安全體現在:數據覆蓋
二、HashMap線程不安全、死循環、數據丟失、數據覆蓋的原因
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null) //此處是判斷是否進行了hash碰撞tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}其中第六行代碼是判斷是否出現hash碰撞,假設兩個線程A、B都在進行put操作,并且hash函數計算出的插入下標是相同的,當線程A執行完第六行代碼后由于時間片耗盡導致被掛起,而線程B得到時間片后在該下標處插入了元素,完成了正常的插入,然后線程A獲得時間片,由于之前已經進行了hash碰撞的判斷,所有此時不會再進行判斷,而是直接進行插入,這就導致了線程B插入的數據被線程A覆蓋了,從而線程不安全!!!
除此之前,還有就是代碼的第38行處有個++size,我們這樣想,還是線程A、B,這兩個線程同時進行put操作時,假設當前HashMap的zise大小為10,當線程A執行到第38行代碼時,從主內存中獲得size的值為10后準備進行+1操作,但是由于時間片耗盡只好讓出CPU,線程B快樂的拿到CPU還是從主內存中拿到size的值10進行+1操作,完成了put操作并將size=11寫回主內存,然后線程A再次拿到CPU并繼續執行(此時size的值仍為10),當執行完put操作后,還是將size=11寫回內存,此時,線程A、B都執行了一次put操作,但是size的值只增加了1,所有說還是由于數據覆蓋又導致了線程不安全!!!
三、如何使HashMap在多線程情況下進行線程安全操作?
使用 Collections.synchronizedMap(map),包裝成同步Map,原理就是在HashMap的所有方法上synchronized
synchronized 關鍵字,代表這個方法加鎖,相當于不管哪一個線程(例如線程A),運行到這個方法時,都要檢查有沒有其它線程B(或者C、 D等)正在用這個方法(或者該類的其他同步方法),有的話要等正在使用synchronized方法的線程B(或者C 、D)運行完這個方法后再運行此線程A,沒有的話,鎖定調用者,然后直接運行!!!
例如:Collections.SynchronizedMap#get()
public V get(Object key) {synchronized (mutex) {return m.get(key);} }原文轉自:https://juejin.cn/post/6917526751199526920
總結
以上是生活随笔為你收集整理的HashMap线程不安全的原因和解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android源码完全解析——View的
- 下一篇: 各985大学计算机考研科目,又一985调