您的位置:首页 > Web前端

正确理解PhantomReference

2014-03-18 11:44 162 查看
phantom reachable - An object is not strongly, softly, nor weakly reachable, has been
determined to not be resurrectable by any finalizer (if it declares a finalize() method itself, then its finalizer will have been run), and is reachable from the roots via one or more (uncleared) phantom reference objects. As soon as an object referenced by
a phantom reference object becomes phantom reachable, the garbage collector will enqueue it. The garbage collector will never clear a phantom reference. All phantom references must be explicitly cleared by the program. 

这段话说明了phantom
reachable与strongly, softly, weakly reachable的区别,不好理解的话在“if
it declares a finalize() method itself, then its finalizer will have been run“。

public class E {
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new F(), queue);
System.out.println(ref.get());

Object obj = null;
obj = queue.poll();
System.out.println(obj);

System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(ref.get());
obj = queue.poll();

System.out.println(obj);
}
}

class F{

}
先看上面这个例子,运行结果如下:

null

null

null

java.lang.ref.PhantomReference@10b30a7

这个结果正常,符合对PhantomReference的文档说明,PhantomReference引用的对象是unreachable的,即使未被垃圾回收器回收,通过get方法返回的也是空。接下来修改一下上面的实例:

public class E {
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new F(), queue);
System.out.println(ref.get());

Object obj = null;
obj = queue.poll();
System.out.println(obj);

System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(ref.get());
obj = queue.poll();

System.out.println(obj);
}
}

class F{
@Override
protected void finalize() throws Throwable {
System.out.println("======================");
super.finalize();
}
}
运行的结果:

null

null

======================

null

null

上一段代码唯一的区别就是F类重载了finalize方法,重载之后通过gc回收后,却没有加入到ReferenceQueue之中。然后再稍微修改上面的代码:

public class E {
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new F(), queue);
System.out.println(ref.get());

Object obj = null;
obj = queue.poll();
System.out.println(obj);

System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.gc();//重新执行垃圾回收

System.out.println(ref.get());
obj = queue.poll();

System.out.println(obj);
}
}

class F{
@Override
protected void finalize() throws Throwable {
System.out.println("======================");
super.finalize();
}
}


这段代码的区别是在多执行了一次System.gc(),结果如下:

null

null

======================

null

java.lang.ref.PhantomReference@10b30a7

多执行一次System.gc()之后,就正常加入到了ReferenceQueue队列中了,其原因就是“if
it declares a finalize() method itself, then its finalizer will have been run“,因为第一次执行GC的时候,F实例的状态为finalizable状态,即有finalize方法没有被执行。而第二次运行gc的时候,F实例的finalize方法已经执行完成,所以能正常加入ReferenceQueue。在第一段代码中,因为没有重载finalize的方法,java虚拟机会完成自动优化。其实这样做的目的是避免在finalize的方法中出现对象再生的情况。这个跟weakReference有着明显的区别,这一点也可以更可靠的监视一个对象是否被回收。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: