WeakHashMap中的疑惑

private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

Entry(Object key, V value,
    ReferenceQueue<Object> queue,
    int hash, Entry<K,V> next) {
        super(key, queue);
        this.value = value;
        this.hash  = hash;
        this.next  = next;
}

Entry的构造方法中,通过调用父类WeakReference的构造方法,绑定keyqueue
key被GC回收掉之后,请问queue中存放的是指向key的弱引用么?
如果是的话

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

expungeStaleEntries方法中,从queuepoll出来的东西,为什么可以强制类型转换成Entry
实际上queue中存放的是key所对应的Entry吗?
看了几遍源码也没有看到有这样的一个过程,求解答,谢谢。

阅读 2k
1 个回答

LZ可参看Reference.tryHandlePending

static boolean tryHandlePending(boolean waitForNotify) {
        Reference<Object> r;
        Cleaner c;
        try {
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    // 'instanceof' might throw OutOfMemoryError sometimes
                    // so do this before un-linking 'r' from the 'pending' chain...
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                    // unlink 'r' from 'pending' chain
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    if (waitForNotify) {
                        lock.wait();
                    }
                    // retry if waited
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
            Thread.yield();
            // retry
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }

        // Fast path for cleaners
        if (c != null) {
            c.clean();
            return true;
        }

        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r); 
        return true;
    }

queue中的对象都是Reference实例,也就是Entry对象。

需要说明的是,Reference类有个全局变量的pending属性(也是Reference类型)和一个private变量discovered。纵观全文没有地方对pending赋值,查看文档说明,这个属性就是等待入队的列表。JVM在GC过程中会把即将回收的Reference赋值给pending,通过另一个属性discovered,把即将enqueue的Reference对象链接起来。

if (q != ReferenceQueue.NULL) q.enqueue(r); 

很容易看到入队的是Reference实例,也就是Entry

    private T referent;         /* Treated specially by GC */

WeakHashMap的Entry‘弱键’就是referent,当弱键GC回收,将会把此reference对象加入到referenceQueue中,对于外部程序,可以通过操作queue来做相应的处理。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题