WeakReference(弱引用)类是Reference(引用)抽象类的四大子类之一,只被弱引用持有的对象被称为弱可达(weakly reachable)对象。在Java中关于弱引用的定义是:弱引用等价于无引用,其存在无法对对象的生命周期产生任何影响,即对象的诞生、初始化、使用及回收完全与弱引用无关。这不禁会令人产生疑惑…如果弱引用就是无引用,那引入所谓的弱引用又有什么意义呢?这不是脱裤子放屁多次一举吗?
事实上有这样的疑惑是非常正常的,因为基本上所有的资料都会在有意或无意中将弱引用和无引用画上等号。如此叙述其实并没有错,但覆盖面过于广泛,从而令学习者无法真正明晰两者的区别。想要真正明白两者差异需要结合更高等级的引用加以对比,以强引用举例:一个对象拥有一个强引用以及九个弱引用和一个对象拥有十个强引用有区别吗?有!而且非常大!前者只需断开一个强引用即可GC回收,而后者却需要断开所有的十个强引用才可以。故而可知,弱引用与无引用的等价性仅限于GC方面,即两者都不会成为GC回收对象的影响因素;但访问方面,软引用则与强引用等价,即两者都可以成为对象的访问通道。
弱引用类常用于帮助GC回收。很多资料都会说弱引用适合用作缓存,可但凡思考过其特性的话应该都不会这么想…一个需要配合强引用才能够保证自身存在的对象适合做哪门子缓存?这不就是个常规的强引用对象么?真正适合做缓存的应该是软引用才对。基于可有可无的引用强度,即使是在没有共存强引用的环境下,只要空闲内存充裕,软引用自身也能够保证热点数据持久存在,这与缓存的运用场景是高度契合的。弱引用的作用主要是用于帮助GC回收,就像上文中举例的场景:一个拥有一个强引用以及九个弱引用的对象和一个拥有十个强引用的对象哪个更容易被GC回收?显然是前者,因为其只需要断开一个强引用就可以了。这个特性在实际开发中非常有用,不仅可以处理遗漏/难以/无法断开一些比较隐秘的强引用而使得对象无法被GC回收最终导致OOM的情况,也有助于简化GC回收。
/**
* Weak reference objects, which do not prevent their referents from being
* made finalizable, finalized, and then reclaimed. Weak references are most
* often used to implement canonicalizing mappings.
* 弱引用对象,它不阻止它们的所指对象被设定为可终结、最终完成,然后被回收。弱引用最常用于实现规范化映射。
*
* Suppose that the garbage collector determines at a certain point in time
* that an object is weakly
* reachable. At that time it will atomically clear all weak references to
* that object and all weak references to any other weakly-reachable objects
* from which that object is reachable through a chain of strong and soft
* references. At the same time it will declare all of the formerly
* weakly-reachable objects to be finalizable. At the same time or at some
* later time it will enqueue those newly-cleared weak references that are
* registered with reference queues.
* 假设垃圾收集器在某个时间点确定一个对象是弱可达的。此时,它将自动清除该对象以及可通过强/软引用链访问该对象的弱可达对象的所有弱引用。
* 与此同时,它将声明所有以前弱可达对象是可终结的(可回收的)。在同一时间或稍后的某个时间,它将对那些注册在引用队列中的新清除的弱引用进行入队。
*
* @author Mark Reinhold
* @since 1.2
*/
public class WeakReference<T> extends Reference<T> {
...
}
public WeakReference(T referent) —— 只指定所指对象,不注册引用队列。可知,WeakReference(弱引用)类可不搭配引用队列使用。
/**
* Creates a new weak reference that refers to the given object. The new
* reference is not registered with any queue.
*
* @param referent object the new weak reference will refer to
*/
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue super T> q) —— 指定所指对象,并注册引用队列。
/**
* Creates a new weak reference that refers to the given object and is
* registered with the given queue.
*
* @param referent object the new weak reference will refer to
* @param q the queue with which the reference is to be registered,
* or null if registration is not required
*/
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}