>  기사  >  Java  >  Java Reference 소스코드 분석 코드에 대한 자세한 설명

Java Reference 소스코드 분석 코드에 대한 자세한 설명

高洛峰
高洛峰원래의
2017-03-19 15:37:561771검색

@(Java)[Reference]

Java 참조 소스 코드 분석

Referenceobject는 다른 개체에 대한 참조를 캡슐화하며 특정 개체에서 일반 개체처럼 작동할 수 있습니다. 제한 사항이 있으므로 가비지 수집기와의 상호 작용이 지원됩니다. 즉, Reference 개체를 사용하여 다른 개체를 참조할 수 있지만 결국에는 가비지 수집기에 의해 재활용됩니다. 개체가 재활용된 후 개체의 도달 가능성에 대한 변경 사항을 알리기 위해 프로그램에 알림이 필요한 경우가 있습니다.
Java는 높은 수준부터 낮은 수준까지 네 가지 유형의 참조를 제공합니다. FinalReference, SoftReference, WeakReference 및 PhantomReference. 그 중 FinalReference는 외부 이용이 불가능합니다. 각 유형은 서로 다른 접근성 수준에 해당합니다.

소개

강한 참조 FinalReference

강한 참조는 Object obj = new Object();, obj는 강력한 참조입니다.

SoftReference

강한 참조는 아니지만 소프트 참조 개체를 통해 액세스할 수 있는 소프트 참조입니다. 소프트 참조 개체의 경우 가비지 수집기는 메모리가 부족한 경우(OOM 예외가 발생하기 전)에만 소프트 참조가 가리키는 개체를 재활용하기로 결정합니다. 소프트 참조는 메모리에 민감한 캐시를 구현하는 데 자주 사용됩니다.

SoftReference<Object> softRef = new SoftReference<Object>(new Object());
WeakReferenceWeakReference

약한 참조, 강한 참조와 소프트 참조는 아니지만 약한 참조 개체를 통해 접근할 수 있습니다. 약하게 참조된 객체는 메모리가 충분한지 여부에 관계없이 가비지 수집기가 발견하는 한 재활용됩니다. 실제 적용은 Weak

HashMap 등을 참고하세요.

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

이 큐는 참조의 구성원으로서 위의 세 가지 참조 유형과 조합하여 사용할 수 있습니다. 이 큐의 기능은 다음과 같습니다. 참조를 생성할 때 큐를 등록합니다. 참조에 의해 참조된 개체가 가비지 수집기에 의해 재활용되면 참조는 알림 메커니즘과 동일한 대기열에 배치됩니다.

예제 데모 1:

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;

Status에는 몇 가지 중요한 속성이 있습니다. 🎜>그림

详解Java Reference源码分析代码내부 클래스 ReferenceHandler

ReferenceHandler는 Reference의 정적 내부 클래스로, 보류 중인 대기열의 참조 인스턴스를 다른 대기열에 추가하는 데 사용됩니다. ReferenceQueue(참조의 큐에 따라 다름) 보류 중인 요소는 GC에 의해 추가됩니다.

참고: 여기서는 보류 중인 대기열이 잠겨 있습니다. 개인적으로 GC가 CMS 동시 수집을 사용할 때와 같이 ReferenceHandler가 있는 스레드와 동시에 GC 스레드가 실행될 수 있기 때문이라고 생각합니다.

다음 코드에서 볼 수 있듯이

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

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.