ReferenceQueue使用样列

  • Strongly reachable: An object that can be accessed by a strong reference.
  • Softly reachable: An object that is not strongly reachable and can be accessed through a soft reference.
  • Weakly reachable: An object that is not strongly or softly reachable and can be accessed through a weak reference.
  • Phantomly reachable: An object that is not strongly, softly, or weakly reachable, has been finalized, and can be accessed through a phantom reference.
  • Clear: Setting the reference object's referent field to null and declaring the object in the heap that the reference class referred to as finalizable.

The SoftReference class

A typical use of the SoftReference class is for a memory-sensitive cache. The idea of a SoftReference is that you hold a reference to an object with the guarantee that all of your soft references will be cleared before the JVM reports an out-of-memory condition. The key point is that when the garbage collector runs, it may or may not free an object that is softly reachable. Whether the object is freed depends on the algorithm of the garbage collector as well as the amount of memory available while the collector is running.

The WeakReference class

A typical use of the WeakReference class is for canonicalized mappings. In addition, weak references are useful for objects that would otherwise live for a long time and are also inexpensive to re-create. The key point is that when the garbage collector runs, if it encounters a weakly reachable object, it will free the object the WeakReference refers to. Note, however, that it may take multiple runs of the garbage collector before it finds and frees a weakly reachable object.

The PhantomReference class

The PhantomReference class is useful only to track the impending collection of the referring object. As such, it can be used to perform pre-mortem cleanup operations. A PhantomReference must be used with the ReferenceQueue class. The ReferenceQueue is required because it serves as the mechanism of notification. When the garbage collector determines an object is phantomly reachable, thePhantomReference object is placed on its ReferenceQueue. The placing of the PhantomReference object on the ReferenceQueue is your notification that the object the PhantomReference object referred to has been finalized and is ready to be collected. This allows you to take action just prior to the object memory being reclaime

public class RefferenceTest {

    public static void main(String[] args) throws InterruptedException {
        
        Test t1 = new Test();
        ReferenceQueue<Test> q1 = new  ReferenceQueue<Test>();
        WeakReference<Test> weakref = new WeakReference<Test>(t1,q1);
        
        Test t2 = new Test();
        ReferenceQueue<Test> q2 = new  ReferenceQueue<Test>();
        PhantomReference p = new PhantomReference<Test>(t2,q2);
        
        
        byte[] t3 = new byte[1024*1024*20];
        ReferenceQueue<byte[]> q3 = new  ReferenceQueue<byte[]>();
        SoftReference<byte[]>  soft = new SoftReference<byte[]>(t3,q3);
        t3=null;
        t2=null;
        t1=null;
        
        System.gc();
        
        ArrayList<byte[]> a = new ArrayList<byte[]>();

        while(true){
            if(weakref.get()==null){
                System.out.println("weakref==null");
                Reference r = q1.poll();
                if(r!=null){
                    System.out.println("q1=="+r.getClass().getName());
                }
            }

            
            Reference r2 = q2.poll();
            if(r2!=null){
                System.out.println("q2=="+r2.getClass().getName());
            }
            
            if(soft.get()==null){
                System.out.println("q3=="+q3.poll().getClass().getName());
                System.out.println("soft==null");
            }
            a.add(new byte[1024*1024*2]);
            Thread.sleep(1000);
        }

    }
}

 

ReferenceQueue的用法一般是如下:创建一个Reference的子类,通过它把可能被回收的key和一些其他数据关联起来。

ReferenceQueue里会拿到这个Reference对象本身,但是这个时候,referent已经是null了,所以一般的用处就是在这个时候通知其他对象,这个时候就必须在Reference对应里面有额外的数据。

那就是为什么通常都必须扩展创建一个Reference的子类。 下面是WeakHashMap里面的entry的实现,它的作用就是当key被回收后,然后通过额外的数据可以检索到对应的Entry,然后把value删除。

**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;

/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}

@SuppressWarnings("unchecked")
public K getKey() {
return null;
}

public V getValue() {
return value;
}

public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}

public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
K k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
V v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
}

 

又或者像下面这样把Reference和其它数据通过HashMap给绑定起来。Reference里面的referent和其它数据具有关联性。

下面代码的意思是向外部代码返回一个WrappedCloseable的包装对象,包含一个指向实际对象的引用,功能由实际的对象带执行。

当WrappedCloseable对象不在被外部代码引用时,GC会回收掉它,然后把对应的WeakReference实例被加入到ReferenceQueue里面。

从quue里面拿到这个WeakReference实例,然后到HashMap里面查找,就知道是哪个Closeable实例对应的包装对象被回收了,然后就可以把它给关闭了。

 class WrappedCloseable {
     Closeable c;
  }

  Map<Reference<WrappedClobseable>, Closeable> m = new HashMap();
  ReferenceQueue<WrappedClobseable> reaped = new ReferenceQueue<WrappedClobseable>();

  WrappedClobseable mt = new WrappedClobseable();
  mt.c = new Closeable();

  Reference<WrappedClobseable> refBack = new WeakReference<WrappedClobseable>(mt, reaped);
  
  m.put(refBack, mt.c);
  mt = null;
  System.gc();
  Reference<Closeable> rf = reaped.poll();
  while (rf != null) {
    m.get(rf).close(); 
    rf = reaped.poll();
  }
  

 

posted @ 2016-03-10 18:51  princessd8251  阅读(197)  评论(0)    收藏  举报