使用软引用构建敏感数据的缓存

[align=center][size=large]使用软引用构建敏感数据的缓存[/size][/align]

一、实现原理

1.应用场景
查询频率较高的数据;每次查询均需要通过接口与数据库交互,构建对象仍需要占用一部分内存;即便上次查询的结果仍在内存中还未被GC回收但仍需要再次进行相同的查询操作;
将查询结果放入内存--大量占用内存空间,增加发生内存溢出的可能;
每次都重新查询--当前的查询结果使用完毕后,实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象
折中的方法,能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度

2.软引用的特点
对于软引用关联着的对象,如果内存充足,则垃圾回收器不会回收该对象,如果内存不够了,就会回收这些对象的内存

3.软引用配合引用队列
软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

二、代码实现

实现思想
[list]
[*]工具类使用懒汉模式的单例实现,避免多线程调用时出现问题,对外接口使用synchronized 关键字修饰
[*]构建缓存,使用Hashtable,key:存储内容的唯一标识,value:存储对象的软引用实现;取元素时,若此缓存中存在,则说明此时对象未被回收、或已被回收,但软引用在引用队列中未被清除;若无,说明存储的对象已被GC;
[*]构建软引用队列,泛型 T 为要存储的对象,当软引用所依赖的对象被GC回收后,JVM将此软引用加入到与之关联的引用队列中。即,此时在等待GC到达 out of memory 前回收此时占用的内存,故每次放入新的对象前,先判断此队列是否有值,若有,主动释放所占用的内存空间
[/list]



/**
* 员工信息类
*/
public class Employee {

private String id ; // 主键

private String name ; // 姓名

private String department ; // 部门

private Double salary ; // 工资

public Employee(String id){
this.id = id ;
}

public Employee(String id, String name, String department, Double salary) {
super();
this.id = id;
this.name = name;
this.department = department;
this.salary = salary;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDepartment() {
return department;
}

public void setDepartment(String department) {
this.department = department;
}

public Double getSalary() {
return salary;
}

public void setSalary(Double salary) {
this.salary = salary;
}

@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", department="
+ department + ", salary=" + salary + "]";
}
}






import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Hashtable;

/**
* 员工信息缓存
*/
public class EmployeeCache {

// 单例模式:懒汉式
private static EmployeeCache employeeCache ;

private EmployeeCache(){
// 构造缓存对象时,初始化缓存容器、软索引队列
cache = new Hashtable<String, EmployeeCache.EmployeeRef>();
queue = new ReferenceQueue<Employee>();
}

public synchronized static EmployeeCache getInstance(){
if(null == employeeCache){
employeeCache = new EmployeeCache();
}
return employeeCache;
}

// 缓存容器
private static Hashtable<String,EmployeeRef> cache = null;
// 软索引队列
private static ReferenceQueue<Employee> queue = null ;

/**
* 私有内部类:Employee 的软索引对象
*/
private class EmployeeRef extends SoftReference<Employee>{
private String uniqueKey = "";
public EmployeeRef(Employee referent, ReferenceQueue<? super Employee> q) {
super(referent, q);
this.setUniqueKey(referent.getId());
}
public void setUniqueKey(String uniqueKey) {
this.uniqueKey = uniqueKey;
}
}

/**
* 向缓存中添加元素
*/
public void put(Employee employee){
// 清空已在引用队列中的软索引对象,释放空间
clearReferenceQueue();
EmployeeRef ref = new EmployeeRef(employee, queue);
cache.put(ref.uniqueKey, ref);
}

private void clearReferenceQueue(){
EmployeeRef ref = null ;
// 引用队列中的数据出队列
while((ref = (EmployeeRef)queue.poll()) != null){
// 同时清除该软引用作为KEY的对象内容
cache.remove(ref.uniqueKey);
}
}

/**
* 从缓存中取出元素
* @param key
* @return
*/
public Employee get(String key){

Employee employee = null ;
if(cache.containsKey(key)){
EmployeeRef employeeRef = cache.get(key);
employee = employeeRef.get();
}
if(null == employee){
employee = new Employee(key);
EmployeeRef ref = new EmployeeRef(employee, queue);
cache.put(key, ref);
}
return employee ;
}
}





public class EmployeeCacheMain {

private static EmployeeCache cache = EmployeeCache.getInstance();
/**
* @param args
*/
public static void main(String[] args) {
Employee e1 = new Employee("1", "张三", "测试部门", 10000.0);
Employee e2 = new Employee("2", "李四", "开发部门", 15000.0);
cache.put(e1);
cache.put(e2);

Employee employee = cache.get("1");
System.out.println(employee.toString());
e2.setDepartment("测试部门");
cache.put(e2);
System.out.println(cache.get("2").getDepartment());
}

}



博文参考:
[url=http://www.importnew.com/20468.html]java引用类型[/url]
[url=http://blog.csdn.net/zmx729618/article/details/54093075]浅谈java对象引用及对象赋值[/url]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值