三、如何實現線程安全的HashMap


 1、爲什麼HashMap線程不安全?
 transient Node<K,V>[] table;
 
 static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
}
 HashMap內部存儲是一個Node數組(默認大小爲16),所有hash值相同(即產生了衝突)的key會存儲到同一鏈表裏。
 (1)假設正好存在兩個put的key發生了碰撞(hash值相同),那麼根據HashMap的實現,這兩個key會添加到數組的同一個位置,這樣就會發生其中一個key的value被覆蓋。
 (2)如果多個線程同時檢測到元素的個數超過(數組大小*負載因子),這樣就會發生多個進程同時對Node數組進行擴容,都在重新計算元素位置以及複製數據,但是最終只有一個線程擴容後的數組會賦給table,也就是說其他線程的都會丟失,並且各自線程put的數據也丟失。
2、如何線程安全的使用HashMap?
    .HashTable
    .ConcurrentHashMap
    .Synchronized Map


    (1)//Hashtable
    Map<String, String> hashtable = new Hashtable<>();
    HashTable源碼中使用synchronized來保證線程安全的,所以當一個線程訪問HashTable的同步方法時,其他線程也要訪問就會被阻塞。
    (2)//synchronizedMap
    // synchronizedMap方法
    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
       return new SynchronizedMap<>(m);
    }
    // SynchronizedMap類
    private static class SynchronizedMap<K,V>
       implements Map<K,V>, Serializable {
       private static final long serialVersionUID = 1978198479659022715L;
 
       private final Map<K,V> m;     // Backing Map
       final Object      mutex;        // Object on which to synchronize
 
       SynchronizedMap(Map<K,V> m) {
           this.m = Objects.requireNonNull(m);
           mutex = this;
       }
 
       SynchronizedMap(Map<K,V> m, Object mutex) {
           this.m = m;
           this.mutex = mutex;
       }
 
       public int size() {
           synchronized (mutex) {return m.size();}
       }
       public boolean isEmpty() {
           synchronized (mutex) {return m.isEmpty();}
       }
       public boolean containsKey(Object key) {
           synchronized (mutex) {return m.containsKey(key);}
       }
       public boolean containsValue(Object value) {
           synchronized (mutex) {return m.containsValue(value);}
       }
       public V get(Object key) {
           synchronized (mutex) {return m.get(key);}
       }
 
       public V put(K key, V value) {
           synchronized (mutex) {return m.put(key, value);}
       }
       public V remove(Object key) {
           synchronized (mutex) {return m.remove(key);}
       }
       // 省略其他方法
   }
    調用synchronizedMap()方法後會返回一個SynchronizedMap類的對象,而在SynchronizedMao類中使用了synchronized同步關鍵字來保證對Map的操作是安全的。(synchronized
    一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。)
    (3)//ConcurrentHashMap
    Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章