java的四种引用类型

欢迎查看Eetal的第十四篇博客–java的四种引用类型

引用队列

ReferenceQueue,引用队列内部维护一个Lock锁,除了强引用,其他类型引用都包含一个可以传入引用队列的构造函数
引用的对象在即将被回收时,会把绑定了引用队列的引用加入引用队列
然后回收该对象,因为这时其会变为InActive(死亡 )

Reference抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
   /*引用实例处于四种可能的内部状态之一:
*
*活性:由垃圾收集器进行特殊处理。一些
*收集器检测到referent已更改为适当的状态,
*它将更改实例的状态为挂起或不活动,具体取决于实例是否在队列中注册已创建。
*在前一种情况下,它还将实例添加到挂起的引用列表。
*新创建的实例处于活动状态。
*
*挂起:挂起引用列表的元素,等待被引用处理程序线程排队。
*未注册的实例从未处于这种状态。
*
*排队:处于等待加入引用队列的等待队列,(因为加入引用队列的方法需要获取锁)
*
*不活动:没什么可做的。一旦一个实例变为非活动状态,状态永远不会改变。
*
*状态在队列和下一个字段中编码如下:
*
*active:queue=referencequeue,注册实例,
*或referencequeue.null,如果它未注册到队列;
*next=NULL。
*
*挂起:queue=referencequeue,实例已注册;
*next=this
*
*排队:queue=referencequeue.enqueued;
*next=following instance
*在队列中,或者在列表的末尾。
*
*非活动:queue=referencequeue.null;
*next=this。
*
*使用此方案,收集器只需按顺序检查下一个字段确定引用实例是否需要特殊处理:如果下一个字段为空,则实例处于活动状态;
*如果为非空,收集器应该正常处理该实例。
*确保并发收集器可以发现活动引用不干扰可能应用的应用程序线程的对象enqueue()方法到这些对象,
*收集器应链接通过发现的字段发现的对象。发现的字段还用于链接挂起列表中的引用对象。
*/

Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
private T referent; /* Treated specially by GC */

volatile ReferenceQueue<? super T> queue;

网上大部分博客对于四种引用的说法都不准确,不去关心为何垃圾回收时会将对应引用加入对应引用队列
这里留意抽象类里的注释Treated specially by GC(被gc特殊对待)
具体过程就是,当满足了该引用对象被回收的条件时(在没有强引用引用他的前提下)
将该引用加入引用队列,并且该引用队列不再引用该对象(清除,注意虚引用在此处不同,虚引用需要等到对象上所有的引用清除以后才清除)
同时该对象也会变为死亡状态,会被垃圾回收器回收
接下来讲讲各个引用的条件

强引用

没什么好说的
java默认的引用类型,就是强引用类型
比如
Object o;
这就是一个强引用,只是没有引用对象

软引用

被软引用的对象在垃圾回收器线程扫描到且当jvm内存不足时,该软引用就会不再引用该对象
软引用可以与引用队列搭配使用
使用方式(传递对象)

SoftReference sr = new SoftReference(new Object());
sr.get(); //返回软引用对象,此处为Object类型

弱引用

被弱引用的对象在垃圾回收器线程扫描到时,该弱引用就会不再引用该对象
弱引用可以与引用队列搭配使用

WeakReference wr = new WeakReference(new Object());
wr.get(); //返回弱引用对象,此处为Object类型

虚引用

虚引用并不影响对象的生命周期
虚引用必须与引用队列搭配使用
虚引用并不可访问引用对象,get总是返回null
虚引用需要等到对象上所有的引用清除以后才清除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class PhantomReference<T> extends Reference<T> {

/**
* Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/
public T get() {
return null;
}
.....
}

ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (new Object(), queue);
pr.get();//返回null

验证代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class RefferenceDemo {
static ReferenceQueue<Object> rq = new ReferenceQueue<Object>();
static Reference wr;
public static void test() {
wr = new WeakReference(new Object(),rq);
System.out.println(wr.get().hashCode());

}
public static void main(String[] args) {
test();
//Object o = wr.get(); //解除注释会增加强引用,则调用gc也不会回收,引用队列poll为null
//注释没有强引用,则调用gc会回收,引用队列poll为不为null
System.gc();
System.out.println(wr.get());
wr = rq.poll();
System.out.println("poll:"+wr+",getValue:"+wr.get());
System.out.println("poll:"+rq.poll());
System.out.println(wr.get());
}
}

输出

1
2
3
4
5
118352462
null
poll:java.lang.ref.WeakReference@5c647e05,getValue:null
poll:null
null

请移步

个人主页: yangyitao.top