2019-03-03——Java引用包 引用與引用隊(duì)列

Java的引用和引用隊(duì)列

Java的軟引用,弱引用和虛引用在都是繼承了Reference這個(gè)類,而且經(jīng)常配合ReferenceQueue來(lái)使用。接下來(lái)我們將了解一下這兩個(gè)類。

Reference

主要是負(fù)責(zé)內(nèi)存的一個(gè)狀態(tài),當(dāng)然它還和java虛擬機(jī),垃圾回收器打交道。Reference類首先把內(nèi)存分為4種狀態(tài)Active,Pending,Enqueued,Inactive。

  • Active,一般來(lái)說(shuō)內(nèi)存一開(kāi)始被分配的狀態(tài)都是 Active
  • Pending 大概是指快要被放進(jìn)隊(duì)列的對(duì)象,也就是馬上要回收的對(duì)象
  • Enqueued 就是對(duì)象的內(nèi)存已經(jīng)被回收了,我們已經(jīng)把這個(gè)對(duì)象放入到一個(gè)隊(duì)列中,方便以后我們查詢某個(gè)對(duì)象是否被回收
  • Inactive就是最終的狀態(tài),不能再變?yōu)槠渌鼱顟B(tài)

主要屬性

private T referent;
volatile ReferenceQueue<? super T> queue;
Reference next;
transient private Reference<T> discovered; 
private static Reference<Object> pending = null;
  • referent表示其引用的對(duì)象,即在構(gòu)造的時(shí)候需要被包裝在其中的對(duì)象。GC會(huì)根據(jù)不同Reference來(lái)特別對(duì)待
  • queue 是對(duì)象即將被回收時(shí)所要通知的隊(duì)列。當(dāng)對(duì)象即將被回收時(shí),整個(gè)reference對(duì)象,而不僅僅是被回收的對(duì)象,會(huì)被放到queue 里面,然后外部程序即可通過(guò)監(jiān)控這個(gè) queue 即可拿到相應(yīng)的數(shù)據(jù)了。
  • next 即當(dāng)前引用節(jié)點(diǎn)所存儲(chǔ)的下一個(gè)即將被處理的節(jié)點(diǎn)。這個(gè)用于實(shí)現(xiàn)一個(gè)單向循環(huán)鏈表,用以將保存需要由ReferenceHandler處理的引用
  • discovered 表示要處理的對(duì)象的下一個(gè)對(duì)象。
  • pending 是等待被入隊(duì)的引用列表。此屬性保存一個(gè)PENDING的隊(duì)列,配合上述next一起使用

靜態(tài)代碼塊

static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();

        // provide access in SharedSecrets
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }

當(dāng) Refrence 類被加載的時(shí)候,會(huì)執(zhí)行靜態(tài)代碼塊。在靜態(tài)代碼塊里面,會(huì)啟動(dòng) ReferenceHandler 線程,并設(shè)置線程的級(jí)別為最大級(jí)別, Thread.MAX_PRIORITY。

ReferenceHandler

private static class ReferenceHandler extends Thread {

        private static void ensureClassInitialized(Class<?> clazz) {
            try {
                Class.forName(clazz.getName(), true, clazz.getClassLoader());
            } catch (ClassNotFoundException e) {
                throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
            }
        }

        static {
            // pre-load and initialize InterruptedException and Cleaner classes
            // so that we don't get into trouble later in the run loop if there's
            // memory shortage while loading/initializing them lazily.
            ensureClassInitialized(InterruptedException.class);
            ensureClassInitialized(Cleaner.class);
        }

        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }

        public void run() {
            while (true) {
                tryHandlePending(true);
            }
        }
    }

該類是一個(gè)靜態(tài)內(nèi)部類,繼承了Thread類,run方法里是一個(gè)死循環(huán)。

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) {
            // Give other threads CPU time so they hopefully drop some live references
            // and GC reclaims some space.
            // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
            // persistently throws OOME for some time...
            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;
    }

在 tryHandlePending 方法里面,檢查 pending 是否為 null,如果pending不為 null,則將 pending 進(jìn)行 enqueue,否則線程進(jìn)入 wait 狀態(tài)。

ReferenceQueue

引用隊(duì)列,在檢測(cè)到適當(dāng)?shù)目傻竭_(dá)性更改后,垃圾回收器將已注冊(cè)的引用對(duì)象添加到隊(duì)列中,ReferenceQueue實(shí)現(xiàn)了入隊(duì)(enqueue)和出隊(duì)(poll),還有remove操作,內(nèi)部元素head就是泛型的Reference。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 引用的分類 Java 1.2以后,除了普通的引用外,Java還定義了軟引用、弱引用、虛引用等概念。 強(qiáng)引用:GC ...
    劉惜有閱讀 880評(píng)論 0 1
  • ReferenceQueue 引用隊(duì)列,在檢測(cè)到適當(dāng)?shù)目傻竭_(dá)性更改后,垃圾回收器將已注冊(cè)的引用對(duì)象添加到該隊(duì)列中 ...
    tomas家的小撥浪鼓閱讀 36,256評(píng)論 10 59
  • 一、JAVA引用 JAVA中有四種引用,強(qiáng)引用、軟引用、弱引用、虛引用,而這些引用在代碼層次都繼承了Referen...
    小刀JACK閱讀 1,334評(píng)論 0 0
  • 我 一個(gè)從出生就被不公平對(duì)待的少女 從未被人堅(jiān)定的選擇 也從未認(rèn)真對(duì)待過(guò)任何得事 我 來(lái)湖南省常德了的一個(gè)小...
    李清歡呀閱讀 1,034評(píng)論 0 0
  • 2015-10-19 周一 晴 我特別喜歡喜劇。美劇三千,只取兩瓢:《老友記》和《生活大爆炸》。 《老友記》已經(jīng)看...
    韓日記閱讀 1,597評(píng)論 5 17