1
ReferenceQueue queue = new ReferenceQueue();
2
SoftReference ref = new SoftReference( aMyObject , queue );
那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可达对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:
1
SoftReference ref = null ;
2
while ((ref = (SoftReference)q .poll()) != null ) {
3
// 清除 ref
4
}
理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。
3.4通过软可及对象重获方法实现Java对象的高速缓存
利用Java2平台垃圾收集机制的特性以及前述的垃圾对象重获方法,我们通过一个雇员信息查询系统的小例子来说明如何构建一种高速缓存器来避免重复构建同一个对象带来的性能损失。我们将一个雇员的档案信息定义为一个Employee类:
01
public class Employee {
02
private String id ; // 雇员的标识号码
03
private String name ; // 雇员姓名
04
private String department ; // 该雇员所在部门
05
private String Phone ; // 该雇员联系电话
06
private int salary ; // 该雇员薪资
07
private String origin ; // 该雇员信息的来源
08
09
// 构造方法
10
public Employee(String id) {
11
this . id = id;
12
getDataFromlnfoCenter();
13
}
14
15
// 到数据库中取得雇员信息
16
private void getDataFromlnfoCenter() {
17
// 和数据库建立连接井查询该雇员的信息,将查询结果赋值
18
// 给 name, department, plone, salary等变量
19
// 同时将 origin赋值为 "From DataBase"
20
}
21
……
22
}
这个Employee类的构造方法中我们可以预见,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。下面是一个对Employee对象进行缓存的缓存器的定义:
01
import java.lang.ref.ReferenceQueue;
02
import java.lang.ref.SoftReference;
03
import java.util.Hashtable;
04
05
public class EmployeeCache {
06
static private EmployeeCache cache ; // 一个 Cache实例
07
private Hashtable
08
private ReferenceQueue
10
// 继承 SoftReference,使得每一个实例都具有可识别的标识,
11
// 并且该标识与其在 HashMap内的 key相同。
12
private class EmployeeRef extends SoftReference
13
private String _key = "" ;
14
15
public EmployeeRef(Employee em, ReferenceQueue
16
super (em, q);
17
_key = em.getID();
18
}
19
}
20
21
// 构建一个缓存器实例
22
private EmployeeCache() {
23
employeeRefs = new Hashtable
24
q = new ReferenceQueue
25
}
26
27
// 取得缓存器实例
28
public static synchronized EmployeeCache getInstance() {
29
if (cache == null){
30
cache = new EmployeeCache();
31
}
32
return cache ;
33
}
34
35
// 以软引用的方式对一个 Employee对象的实例进行引用并保存该引用
36
private void cacheEmployee(Employee em) {
37
cleanCache(); // 清除垃圾引用
38
EmployeeRef ref = new EmployeeRef(em, q );
39
employeeRefs .put(em.getID(), ref);
40
}
41
42
// 依据所指定的 ID号,重新获取相应 Employee对象的实例
43
public Employee getEmployee(String ID) {
44
Employee em = null ;
45
// 缓存中是否有该 Employee实例的软引用,如果有,从软引用中取得。
46
if ( employeeRefs .containsKey(ID)) {
47
EmployeeRef ref = (EmployeeRef) employeeRefs .get(ID);
48
em = (Emp