Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung des Java-Referenz-Quellcode-Analysecodes

Detaillierte Erläuterung des Java-Referenz-Quellcode-Analysecodes

高洛峰
高洛峰Original
2017-03-19 15:37:561816Durchsuche

@(Java)[Referenz]

Java-Referenz-Quellcode-Analyse

ReferenzObjekt kapselt Referenzen auf andere Objekte und kann unter bestimmten Bedingungen wie gewöhnliche Objekte betrieben werden Einschränkungen wird die Interaktion mit dem Garbage Collector unterstützt. Das heißt, Sie können das Referenzobjekt verwenden, um auf andere Objekte zu verweisen, es wird jedoch am Ende trotzdem vom Garbage Collector recycelt. Manchmal müssen Programme benachrichtigt werden, nachdem ein Objekt recycelt wurde, um das Objekt über eine Änderung der Erreichbarkeit zu informieren.
Java bietet vier verschiedene Referenztypen von hoch bis niedrig: FinalReference, SoftReference, WeakReference und PhantomReference. Unter diesen ist FinalReference nicht für die externe Verwendung verfügbar. Jeder Typ entspricht einem anderen Grad der Zugänglichkeit.

Einführung

Starke Referenz FinalReference

Starke Referenz bedeutet, dass es eine direkt erreichbare Referenz im Programm gibt, ohne dass ein Referenzobjekt wie Object obj = new Object();, obj ist eine starke Referenz.

SoftReference

Soft-Referenz, keine starke Referenz, aber der Zugriff kann über ein Soft-Referenzobjekt erfolgen. Bei Soft-Referenzobjekten entscheidet der Garbage Collector nur dann, das Objekt, auf das die Soft-Referenz zeigt, wiederzuverwenden, wenn nicht genügend Speicher vorhanden ist (bevor eine OOM-Ausnahme ausgelöst wird). Soft-Referenzen werden häufig zur Implementierung speicherempfindlicher Caches verwendet.

SoftReference<Object> softRef = new SoftReference<Object>(new Object());
Weak Reference WeakReference

Schwache Referenz, nicht starke Referenz und weiche Referenz, aber der Zugriff kann über ein schwaches Referenzobjekt erfolgen. Ein schwach referenziertes Objekt wird recycelt, solange es vom Garbage Collector erkannt wird, unabhängig davon, ob der Speicher ausreicht. Für tatsächliche Anwendungen siehe Weak

HashMap usw.

WeakReference<Object> weakRef = new WeakReference<Object>(new Object());
Virtuelle ReferenzPhantomReference

Virtuelle Referenz, diese Referenz muss zusammen mit der Referenzwarteschlange (ReferenceQueue) verwendet werden und wird im Allgemeinen zum Verfolgen der Recyclingaktionen des Garbage Collectors verwendet, z Wenn ein Objekt recycelt wird, wird die Finalize-Methode des Objekts aufgerufen. Diese Aktion kann durch die Verwendung virtueller Referenzen erreicht werden, was auch sicherer ist.

Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
PhantomReference<Object> phantom = new PhantomReference<Object>(obj, refQueue);
ReferenceQueue

Als Mitglied der Referenz kann diese Warteschlange in Kombination mit den oben genannten drei Referenztypen verwendet werden. Die Funktion dieser Warteschlange ist: Beim Erstellen einer Referenz registrieren die Warteschlange zur Referenz: Wenn das von der Referenz referenzierte Objekt vom Garbage Collector recycelt wird, wird die Referenz in die Warteschlange gestellt, was einem Benachrichtigungsmechanismus entspricht.

Beispiel 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);
Quellcode-Analyse

Referenz und ReferenceQueue

In der Referenz gibt es mehrere wichtige Attribute

// 用于保存对象的引用,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;

StatusGraph

详解Java Reference源码分析代码

Interne Klasse ReferenceHandler

ReferenceHandler ist eine statische interne Klasse von Reference, die zum Implementieren von Referenzinstanzen in der ausstehenden Warteschlange Hinzugefügt verwendet wird nacheinander in unterschiedliche ReferenceQueues (abhängig von der Warteschlange in Reference). Die ausstehenden Elemente werden vom GC hinzugefügt.

Hinweis: Die ausstehende Warteschlange ist hier gesperrt. Ich persönlich denke, das liegt daran, dass der GC-Thread möglicherweise gleichzeitig mit dem Thread ausgeführt wird, in dem sich der ReferenceHandler befindet, beispielsweise wenn der GC die gleichzeitige CMS-Sammlung verwendet.
Wie im folgenden Code gezeigt

// 此线程在静态块中启动,即一旦使用了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-Attribut

// 用于标识没有注册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

ruft diese Methode nur über die Referenz auf, die verwendet wird transfer Reference Legen Sie es in die aktuelle Warteschlange

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;
        }
    }
}
Der spezifische Ausführungsprozess

Verwenden Sie das obige Beispiel Demo1 als Analyse

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Java-Referenz-Quellcode-Analysecodes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn