正确理解PhantomReference

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有着明显的区别,这一点也可以更可靠的监视一个对象是否被回收。

猜你喜欢

转载自blog.csdn.net/lxpblsc/article/details/21450831