@(Java)[Referenz]
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.
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.
SoftReferenceSoft-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());
HashMap usw.
WeakReference<Object> weakRef = new WeakReference<Object>(new Object());
Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<>(); PhantomReference<Object> phantom = new PhantomReference<Object>(obj, refQueue);
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);
// 用于保存对象的引用,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;
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); } } }
// 用于标识没有注册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;
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; } } }
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; } } }
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!