1. 程式人生 > >java數據結構之WeakHashMap

java數據結構之WeakHashMap

== must hash 回收 clas iter 父類 構造 help

一、JAVA中的四種引用類型

  1、強引用(StrongReference):強引用是最為普遍的一種引用,如果對象被強引用,那麽垃圾回收器無論如何都不會回收它,當內存不足時會拋出OutOfMemoryError異常。

  2、軟引用(SoftReference):如果一個對象只被軟引用,當內存空間足夠時,垃圾回收器就不會回收它。當內存空間不足時,該對象就會被回收。

  3、弱引用(WeakReference):如果一個對象只被弱引用,觸發GC時,不管內存是否足夠,垃圾回收器都會將其回收。

  4、虛引用(PhantomReference):如果一個對象只有虛引用在引用它,垃圾回收器是可以在任意時候對其進行回收的,虛引用主要用來跟蹤對象被垃圾回收器回收的活動。

二、WeakHashMap源碼分析

  由於WeakHashMap的源碼和HashMap差不多,所以只說一些特別的地方。

  1、WeakHashMap對於鍵值對的引用類型為弱引用,WeakHashMap定義了一個ReferenceQueue來儲存已經被回收了的鍵值對,當我們需要獲取某個鍵值對的時候會先利用ReferenceQueue將WeakHashMap中已經被回收的鍵值對清除掉。

        /**
     * 用來存儲已經被GC的entry
     */
    private final ReferenceQueue<Object> queue = new
ReferenceQueue<>(); /** * 從表中刪除陳舊的條目,通過和ReferenceQueue中進行對比,來進行刪除 */ private void expungeStaleEntries() { for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry
<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator e.value = null; // Help GC size--; break; } prev = p; p = next; } } } }

...

private Entry<K,V>[] getTable() {
        expungeStaleEntries();
        return table;
    }
    
    public int size() {
        if (size == 0)
            return 0;
        expungeStaleEntries();
        return size;
    }
    
    public boolean isEmpty() {
        return size() == 0;
    }
    
    public V get(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null) {
            if (e.hash == h && eq(k, e.get()))
                return e.value;
            e = e.next;
        }
        return null;
    }

  

  2、WeakHashMap的Entry類繼承了WeakReference類,其構造函數中有一個參數queue用來傳入父類構造函數中,ReferenceQueue用來保存被GC的Entry。

Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next)

  3、WeakHashMap的初始化默認參數和HashMap相同,但是其hash方法以及resize方法不同。擴容的時候容量也是將容量變為原來的兩倍

    final int hash(Object k) {
        int h = k.hashCode();
    
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
    
    /**
     * 確定entry的下標位置
     */
    private static int indexFor(int h, int length) {
        return h & (length-1);
    }

java數據結構之WeakHashMap