欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?HashTable與Collections.synchronizedMap源碼深入解析

 更新時間:2022年11月02日 10:27:12   作者:AllenC6  
HashTable是jdk?1.0中引入的產(chǎn)物,基本上現(xiàn)在很少使用了,但是會在面試中經(jīng)常被問到。本文就來帶大家一起深入了解一下Hashtable,需要的可以參考一下

一、類繼承關系圖

二、HashTable介紹

HashTable的操作幾乎和HashMap一致,主要的區(qū)別在于HashTable為了實現(xiàn)多線程安全,在幾乎所有的方法上都加上了synchronized鎖,而加鎖的結果就是HashTable操作的效率十分低下。

不建議使用HashTable,Oracle官方也將其廢棄,建議在多線程環(huán)境下使用ConcurrentHashMap類。

三、HashTable和HashMap的對比

1.線程安全

HashMap是線程不安全的類,多線程下會造成并發(fā)沖突,但單線程下運行效率較高;HashTable是線程安全的類,很多方法都是用synchronized修飾,但同時因為加鎖導致并發(fā)效率低下,單線程環(huán)境效率也十分低;

2.插入null

HashMap允許有鍵為null,值為null;但HashTable不允許鍵或值為null;

3.容量

HashMap底層數(shù)組長度必須為2的冪,這樣做是為了hash準備,默認為16;而HashTable底層數(shù)組長度可以為任意值,這就造成了hash算法散射不均勻,容易造成hash沖突,默認為11;

   public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        table = new Entry<?,?>[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }
    /**
     * Constructs a new, empty hashtable with the specified initial capacity
     * and default load factor (0.75).
     *
     * @param     initialCapacity   the initial capacity of the hashtable.
     * @exception IllegalArgumentException if the initial capacity is less
     *              than zero.
     */
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }
    /**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    public Hashtable() {
        this(11, 0.75f);
    }
    /**
     * Constructs a new hashtable with the same mappings as the given
     * Map.  The hashtable is created with an initial capacity sufficient to
     * hold the mappings in the given Map and a default load factor (0.75).
     *
     * @param t the map whose mappings are to be placed in this map.
     * @throws NullPointerException if the specified map is null.
     * @since   1.2
     */
    public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        putAll(t);
    }

4.Hash映射

HashMap的hash算法通過非常規(guī)設計,將底層table長度設計為2的冪,使用位與運算代替取模運算,減少運算消耗;而HashTable的hash算法首先使得hash值小于整型數(shù)最大值,再通過取模進行散射運算;

int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

5.擴容機制

HashMap創(chuàng)建一個為原先2倍的數(shù)組,然后對原數(shù)組進行遍歷以及然后重新通過位運算計算位置,不管是紅黑樹還是鏈表,都先采取尾插法分成兩條鏈,然后再通過鏈的數(shù)量決定是樹化還是轉鏈表(其實就是把TreeNode變成Node,因為紅黑樹分成兩條鏈后其實就是TreeNode組成的鏈表);HashTable擴容將創(chuàng)建一個原長度2倍的數(shù)組 + 1,然后對原數(shù)組進行遍歷以及rehash,頭插法;

hashTable的擴容:

int newCapacity = (oldCapacity << 1) + 1;

hashTable的頭插法:

        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }

6.結構區(qū)別

HashMap是由數(shù)組+鏈表形成,在JDK1.8之后鏈表長度大于8時轉化為紅黑樹;而HashTable一直都是數(shù)組+鏈表;

四、Collections.synchronizedMap解析

1.Collections.synchronizedMap是怎么實現(xiàn)線程安全的

調用Collections.synchronizedMap實際是給Map包裝成了SynchronizedMap

    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

2.SynchronizedMap源碼

先看屬性:

        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;
        }

通過構造方法,把map傳進來,如果不傳Object mutex參數(shù),mutex就是this

再看一下具體是怎么實現(xiàn)線程安全的:

        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);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

發(fā)現(xiàn)幾乎所有操作Map的代碼,都把mutex作為鎖,獲取到鎖之后去操作Map。

這種和HashTable直接鎖整個方法粒度差不多,都不推薦使用,推薦使用ConcurrentHashMap

到此這篇關于Java HashTable與Collections.synchronizedMap源碼深入解析的文章就介紹到這了,更多相關Java HashTable與Collections.synchronizedMap內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論