詳解Java Reference源碼分析程式碼
@(Java)[Reference]
Java Reference 原始碼分析
Reference物件封裝了其它物件的引用,可以和普通的物件一樣操作,在在一定的限制條件下,支援和垃圾收集器的交互作用。即可以使用Reference對象來引用其它對象,但最後還是會被垃圾收集器回收。程序有時也需要在物件回收後被通知,以告知對象的可及性發生變更。
Java提供了四種不同類型的引用,引用等級從高到低分別為FinalReference,SoftReference,WeakReference,PhantomReference。其中FinalReference並未對外提供使用。每種類型對應著不同程度的可及性。
簡介
強引用FinalReference
#強引用指的是,程式中有直接可達的引用,而不需要透過任何引用對象,如Object obj = new Object();中,obj為強引用。
軟引用SoftReference
軟引用,非強引用,但可以透過軟引用物件來存取。軟引用的對象,只有在記憶體不足的時候(拋出OOM異常前),垃圾收集器會決定回收該軟引用所指向的對象。軟引用通常用於實現記憶體敏感的快取。
SoftReference<Object> softRef = new SoftReference<Object>(new Object());
弱引用WeakReference
弱引用,非強引用和軟引用,但可以透過弱引用物件來存取。弱引用的對象,不管記憶體是否足夠,只要被垃圾收集器發現,該引用的對象就會被回收。實際的應用請見WeakHashMap等。
WeakReference<Object> weakRef = new WeakReference<Object>(new Object());
虛引用PhantomReference
虛引用,該引用必須和引用隊列(ReferenceQueue)一起使用,一般用於實現追蹤垃圾收集器的回收動作,例如在物件被回收的時候,會呼叫該物件的finalize方法,在使用虛引用可以實現該動作,也更加安全。
Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<>(); PhantomReference<Object> phantom = new PhantomReference<Object>(obj, refQueue);
ReferenceQueue
該隊列作為引用中的一員,可以和上述三種引用類型組合使用,該隊列的作用是:建立Reference時,將Queue註冊到Reference中,當該Reference所引用的物件被垃圾收集器回收時,會將該Reference放到該佇列中,相當於一種通知機制。
範例Demo1:
ReferenceQueue queue = new ReferenceQueue(); WeakReference reference = new WeakReference(new Object(), queue); System.out.println(reference); System.gc(); Reference reference1 = queue.remove(); System.out.println(reference1);
原始碼分析
Reference和ReferenceQueue
Reference內部有幾個比較重要的屬性
// 用于保存对象的引用,GC会根据不同Reference来特别对待 private T referent; // 如果需要通知机制,则保存的对对应的队列 ReferenceQueue<? super T> queue; /* 这个用于实现一个单向循环链表,用以将保存需要由ReferenceHandler处理的引用 */ Reference next; static private class Lock { }; // 锁,用于同步pending队列的进队和出队 private static Lock lock = new Lock(); // 此属性保存一个PENDING的队列,配合上述next一起使用 private static Reference pending = null;
狀態圖
內部類別ReferenceHandler
#ReferenceHandler作為Reference的靜態內部類,用於實作將pending佇列裡面的Reference實例依序加入不同的ReferenceQueue中(取決於Reference裡面的queue)。此pending的元素由GC負責加入。
註:這裡對pending佇列進行加鎖,個人認為是因為GC執行緒可能和ReferenceHandler所在的執行緒並發執行,如GC採用CMS並發收集的時候。
如下程式碼所示
// 此线程在静态块中启动,即一旦使用了Reference,则会启动该线程 private static class ReferenceHandler extends Thread { public void run() { for (;;) { Reference r; synchronized (lock) { if (pending != null) { r = pending; Reference rn = r.next; // 从pending中取下一个元素,如果后继为空,则next指向自身 pending = (rn == r) ? null : rn; r.next = r; } else { try { // 没有则等待,后续加入元素会调用lock.notify唤醒 lock.wait(); } catch (InterruptedException x) { } continue; } } // ... ReferenceQueue q = r.queue; // 如果该Reference注册了对应的Queue,则加入到该Queue中 if (q != ReferenceQueue.NULL) q.enqueue(r); } } }
ReferenceQueue屬性
// 用于标识没有注册Queue static ReferenceQueue NULL = new Null(); // 用于标识已经处于对应的Queue中 static ReferenceQueue ENQUEUED = new Null(); static private class Lock { }; /* 互斥锁,用于同步ReferenceHandler的enqueue和用户线程操作的remove和poll出队操作 */ private Lock lock = new Lock(); // 队列 private volatile Reference<? extends T> head = null; // 队列中的元素个数 private long queueLength = 0;
ReferenceQueue.enqueue
只會透過Reference裡要呼叫該方法,用於將Reference放入到目前佇列中
boolean enqueue(Reference<? extends T> r) { synchronized (r) { // 判断是否已经入队了 if (r.queue == ENQUEUED) return false; synchronized (lock) { r.queue = ENQUEUED; // 单向循环 r.next = (head == null) ? r : head; head = r; queueLength++; if (r instanceof FinalReference) { sun.misc.VM.addFinalRefCount(1); } // 通知当前挂起的线程(调用remove时有可能会挂起) lock.notifyAll(); return true; } } }
ReferenceQueue.remove
public Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("Negative timeout value"); } synchronized (lock) { // 从队列中取出一个元素 Reference<? extends T> r = reallyPoll(); // 如果不为空,则直接返回 if (r != null) return r; for (;;) { // 否则等待,由enqueue时notify唤醒 lock.wait(timeout); r = reallyPoll(); if (r != null) return r; if (timeout != 0) return null; } } }
具體執行流程
以上述範例Demo1作為分析
// 创建一个引用队列 ReferenceQueue queue = new ReferenceQueue(); // 创建虚引用,此时状态为Active,并且Reference.pending为空,当前Reference.queue = 上面创建的queue,并且next=null WeakReference reference = new WeakReference(new Object(), queue); System.out.println(reference); // 当GC执行后,由于是虚引用,所以回收该object对象,并且置于pending上,此时reference的状态为PENDING System.gc(); /* ReferenceHandler从pending中取下该元素,并且将该元素放入到queue中,此时Reference状态为ENQUEUED,Reference.queue = ReferenceENQUEUED */ /* 当从queue里面取出该元素,则变为INACTIVE,Reference.queue = Reference.NULL */ Reference reference1 = queue.remove(); System.out.println(reference1);
以上是詳解Java Reference源碼分析程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

在使用IntelliJIDEAUltimate版本啟動Spring...

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...

Redis緩存方案如何實現產品排行榜列表的需求?在開發過程中,我們常常需要處理排行榜的需求,例如展示一個�...
