理解Java中的弱引用(Weak Reference)

1. What——什么是弱引用?

    Java中的弱引用具体指的是java.lang.ref.WeakReference<T>类,咱们首先来看一下官方文档对它作的说明:java

弱引用对象的存在不会阻止它所指向的对象变被垃圾回收器回收。弱引用最多见的用途是实现规范映射(canonicalizing mappings,好比哈希表)。app

假设垃圾收集器在某个时间点决定一个对象是弱可达的(weakly reachable)(也就是说当前指向它的全都是弱引用),这时垃圾收集器会清除全部指向该对象的弱引用,而后垃圾收集器会把这个弱可达对象标记为可终结(finalizable)的,这样它们随后就会被回收。与此同时或稍后,垃圾收集器会把那些刚清除的弱引用放入建立弱引用对象时所登记到的引用队列(Reference Queue)中。函数

   

    实际上,Java中存在四种引用,它们由强到弱依次是:强引用、软引用、弱引用、虚引用。下面咱们简单介绍下除弱引用外的其余三种引用:spa

  • 强引用(Strong Reference):一般咱们经过new来建立一个新对象时返回的引用就是一个强引用,若一个对象经过一系列强引用可到达,它就是强可达的(strongly reachable),那么它就不被回收
  • 软引用(Soft Reference):软引用和弱引用的区别在于,若一个对象是弱引用可达,不管当前内存是否充足它都会被回收,而软引用可达的对象在内存不充足时才会被回收,所以软引用要比弱引用“强”一些
  • 虚引用(Phantom Reference):虚引用是Java中最弱的引用,那么它弱到什么程度呢?它是如此脆弱以致于咱们经过虚引用甚至没法获取到被引用的对象,虚引用存在的惟一做用就是当它指向的对象被回收后,虚引用自己会被加入到引用队列中,用做记录它指向的对象已被销毁。

     

 2. Why——为何使用弱引用?

     考虑下面的场景:如今有一个Product类表明一种产品,这个类被设计为不可扩展的,而此时咱们想要为每一个产品增长一个编号。一种解决方案是使用HashMap<Product, Integer>。因而问题来了,若是咱们已经再也不须要一个Product对象存在于内存中(好比已经卖出了这件产品),假设指向它的引用为productA,咱们这时会给productA赋值为null,然而这时productA过去指向的Product对象并不会被回收,由于它显然还被HashMap引用着。因此这种状况下,咱们想要真正的回收一个Product对象,仅仅把它的强引用赋值为null是不够的,还要把相应的条目从HashMap中移除。显然“从HashMap中移除再也不须要的条目”这个工做咱们不想本身完成,咱们但愿告诉垃圾收集器:在只有HashMap中的key在引用着Product对象的状况下,就能够回收相应Product对象了。显然,根据前面弱引用的定义,使用弱引用能帮助咱们达成这个目的。咱们只须要用一个指向Product对象的弱引用对象来做为HashMap中的key就能够了。设计

 

3. How——如何使用弱引用?

     拿上面介绍的场景举例,咱们使用一个指向Product对象的弱引用对象来做为HashMap的key,只需这样定义这个弱引用对象:对象

productA = new Product(...);
WeakReference<Product> weakProductA = new WeakReference<>(productA);

    如今,若引用对象weakProductA就指向了Product对象productA。那么咱们怎么经过weakProduct获取它所指向的Product对象productA呢?很简单,只须要下面这句代码:队列

Product product = weakProductA.get();

    实际上,对于这种状况,Java类库为咱们提供了WeakHashMap类,使用和这个类,它的键天然就是弱引用对象,无需咱们再手动包装原始对象。这样一来,当productA变为null时(代表它所引用的Product已经无需存在于内存中),这时指向这个Product对象的就是由弱引用对象weakProductA了,那么显然这时候相应的Product对象时弱可达的,因此指向它的弱引用会被清除,这个Product对象随即会被回收,指向它的弱引用对象会进入引用队列中。 内存

    下面咱们来简单地介绍下引用队列的概念。实际上,WeakReference类有两个构造函数:文档

WeakReference(T referent) //建立一个指向给定对象的弱引用
WeakReference(T referent, ReferenceQueue<? super T> q) //建立一个指向给定对象而且登记到给定引用队列的弱引用

    咱们能够看到第二个构造方法中提供了一个ReferenceQueue类型的参数,经过提供这个参数,咱们便把建立的弱引用对象注册到了一个引用队列上,这样当它被垃圾回收器清除时,就会把它送入这个引用队列中,咱们即可以对这些被清除的弱引用对象进行统一管理。get

相关文章
相关标签/搜索