WeakHashMap中关于queue的疑惑( 二 )

之所以能够强转成Entry,其实跟WeakHashMap#put方法相关,您可以参考这个方法:
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for this key, the old * value is replaced. * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @return the previous value associated with \u0026lt;tt\u0026gt;key\u0026lt;/tt\u0026gt;, or * \u0026lt;tt\u0026gt;null\u0026lt;/tt\u0026gt; if there was no mapping for \u0026lt;tt\u0026gt;key\u0026lt;/tt\u0026gt;. * (A \u0026lt;tt\u0026gt;null\u0026lt;/tt\u0026gt; return can also indicate that the map * previously associated \u0026lt;tt\u0026gt;null\u0026lt;/tt\u0026gt; with \u0026lt;tt\u0026gt;key\u0026lt;/tt\u0026gt;.) */ public V put(K key, V value) { Object k = maskNull(key); int h = hash(k); Entry\u0026lt;K,V\u0026gt; tab = getTable(); int i = indexFor(h, tab.length); for (Entry\u0026lt;K,V\u0026gt; e = tab; e != null; e = e.next) { if (h == e.hash \u0026amp;\u0026amp; eq(k, e.get())) { V oldValue = https://www.zhihu.com/api/v4/questions/63932795/e.value; if (value != oldValue) e.value = value; return oldValue; } } modCount++; Entry/u0026lt;K,V/u0026gt; e = tab; tab = new Entry/u0026lt;/u0026gt;(k, value, queue, h, e); if (++size /u0026gt;= threshold) resize(tab.length * 2); return null; }然后看到Entry的声明:
private static class Entry\u0026lt;K,V\u0026gt; extends WeakReference\u0026lt;Object\u0026gt; implements Map.Entry\u0026lt;K,V\u0026gt; {原来Entry的父类就是一个Reference,类图如下所示:
WeakHashMap中关于queue的疑惑

所以,对于线程中的这段代码:
ReferenceQueue\u0026lt;? super Object\u0026gt; q = r.queue;if (q != ReferenceQueue.NULL) q.enqueue(r);在运行时,r的实际类型就是put进去的那个WeakHashMap.Entry。
————————————————————————————————
【WeakHashMap中关于queue的疑惑 】 GC过程中,HotSpot VM对于SoftReference、WeakReference、FinalReference、Phantom Reference的处理过程如下:
ReferenceProcessorStats ReferenceProcessor::process_discovered_references( BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor, GCTimer* gc_timer) { NOT_PRODUCT(verify_ok_to_handle_reflists()); assert(!enqueuing_is_done(), "If here enqueuing should not be complete"); // Stop treating discovered references specially. disable_discovery(); // If discovery was concurrent, someone could have modified // the value of the static field in the j.l.r.SoftReference // class that holds the soft reference timestamp clock using // reflection or Unsafe between when discovery was enabled and // now. Unconditionally update the static field in ReferenceProcessor // here so that we use the new value during processing of the // discovered soft refs. _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock(); bool trace_time = PrintGCDetails \u0026amp;\u0026amp; PrintReferenceGC; // Soft references size_t soft_count = 0; { GCTraceTime tt("SoftReference", trace_time, false, gc_timer); soft_count = process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); // Weak references size_t weak_count = 0; { GCTraceTime tt("WeakReference", trace_time, false, gc_timer); weak_count = process_discovered_reflist(_discoveredWeakRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } // Final references size_t final_count = 0; { GCTraceTime tt("FinalReference", trace_time, false, gc_timer); final_count = process_discovered_reflist(_discoveredFinalRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); } // Phantom references size_t phantom_count = 0; { GCTraceTime tt("PhantomReference", trace_time, false, gc_timer); phantom_count = process_discovered_reflist(_discoveredPhantomRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); } // Weak global JNI references. It would make more sense (semantically) to // traverse these simultaneously with the regular weak references above, but // that is not how the JDK1.2 specification is. See #4126360. Native code can // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer); if (task_executor != NULL) { task_executor-\u0026gt;set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count);}size_tReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists, ReferencePolicy* policy, bool clear_referent, BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor){ bool mt_processing = task_executor != NULL \u0026amp;\u0026amp; _processing_is_mt; // If discovery used MT and a dynamic number of GC threads, then // the queues must be balanced for correctness if fewer than the // maximum number of queues were used. The number of queue used // during discovery may be different than the number to be used // for processing so don\u0026#39;t depend of _num_q \u0026lt; _max_num_q as part // of the test. bool must_balance = _discovery_is_mt; if ((mt_processing \u0026amp;\u0026amp; ParallelRefProcBalancingEnabled) || must_balance) { balance_queues(refs_lists); } size_t total_list_count = total_count(refs_lists); if (PrintReferenceGC \u0026amp;\u0026amp; PrintGCDetails) { gclog_or_tty-\u0026gt;print(", %u refs", total_list_count); } // Phase 1 (soft refs only): // . Traverse the list and remove any SoftReferences whose // referents are not alive, but that should be kept alive for // policy reasons. Keep alive the transitive closure of all // such referents. if (policy != NULL) { if (mt_processing) { RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/); task_executor-\u0026gt;execute(phase1); } else { for (uint i = 0; i \u0026lt; _max_num_q; i++) { process_phase1(refs_lists, policy, is_alive, keep_alive, complete_gc); } } } else { // policy == NULL assert(refs_lists != _discoveredSoftRefs, "Policy must be specified for soft references."); } // Phase 2: // . Traverse the list and remove any refs whose referents are alive. if (mt_processing) { RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/); task_executor-\u0026gt;execute(phase2); } else { for (uint i = 0; i \u0026lt; _max_num_q; i++) { process_phase2(refs_lists, is_alive, keep_alive, complete_gc); } } // Phase 3: // . Traverse the list and process referents as appropriate. if (mt_processing) { RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/); task_executor-\u0026gt;execute(phase3); } else { for (uint i = 0; i \u0026lt; _max_num_q; i++) { process_phase3(refs_lists, clear_referent, is_alive, keep_alive, complete_gc); } } return total_list_count;}


推荐阅读