`

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

阅读更多
使用软引用构建敏感数据的缓存


一、实现原理

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

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

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

二、代码实现

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



/**
 * 员工信息类
 */
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());
	}

}



博文参考:
java引用类型
浅谈java对象引用及对象赋值
分享到:
评论

相关推荐

    Java中四种引用类型详细介绍

    **使用软引用构建敏感数据缓存的示例** 在内存敏感的应用场景中,如雇员信息查询系统,使用软引用可以有效地平衡内存使用和性能。通过创建软引用对象来存储最近访问的雇员信息,当内存不足时,这些软引用对象会被...

    Java对象的强、软、弱和虚引用1

    **软引用构建敏感数据缓存**: 在设计系统时,如雇员信息查询系统,使用软引用可以创建一个内存敏感的缓存。当内存充足时,最近访问过的雇员信息可以保留在缓存中,提高查询效率。而当内存不足时,这些信息作为软...

    三级缓存DiskLruCache+LruCache

    在Android开发中,为了优化应用程序性能...理解并合理使用这些引用类型,对于构建高效、健壮的Android应用至关重要。在图片缓存场景中,结合软引用和弱引用,可以在保证性能的同时,避免内存泄漏,提供更好的用户体验。

    Android_ImageCache

    总结,`Android_ImageCache` 关注的是如何在Android平台上构建一个完整的图片缓存系统,结合了内存缓存、软引用、文件缓存和网络下载等技术,以优化图片加载性能,提高应用的响应速度和用户体验。开发者在实际项目中...

    Java功底之Reference

    1. **软引用(Soft Reference)**:软引用通常用于实现内存敏感的缓存。当系统内存不足时,垃圾收集器会回收软引用指向的对象,以防止系统出现OutOfMemoryError。在回收前,软引用可以被用来检查对象是否还存在。 2...

    j2ee cache framework

    4. **Soft References & Weak References**:Java中的软引用和弱引用可以帮助实现内存敏感的缓存策略。 ### 五、缓存的并发控制与同步 在多线程环境下,缓存的并发控制至关重要。Java的`synchronized`关键字、`...

    Active Record所引用的程序集

    这些引用提供了访问ORM框架所需的所有类型和方法,使得我们可以构建、查询和管理数据模型。 6. **性能考虑**:虽然ORM简化了数据库操作,但它可能会带来一定的性能开销,如额外的内存消耗和查询转换时间。因此,在...

    NHibernate.rar所有需要添加的引用功能包

    总结起来,"NHibernate.rar所有需要添加的引用功能包" 提供了 NHibernate ORM 框架的完整依赖,包括 NHibernate 核心、日志记录、动态代理和特殊集合类型,这些是构建基于 NHibernate 的数据访问层所必需的。...

    ASP.NET4高级程序设计第4版 带目录PDF 分卷压缩包 part1

    11.3 数据缓存 11.3.1 向缓存添加项目 11.3.2 简单的缓存测试 11.3.3 缓存优先级 11.3.4 使用数据源控件的缓存 11.4 缓存依赖 11.4.1 文件和缓存项目依赖 11.4.2 聚合依赖 11.4.3 移除项目回调 ...

    Developer's Guide to Microsoft Enterprise Library, C# Edition

    - **数据加密**:集成加密机制以保护敏感数据的安全性。 - **异常处理**:设计一致的策略来管理在不同架构层中出现的异常。 - **日志记录**:通过内置的日志记录工具或自定义提供程序实现系统日志记录。 - **验证...

    利用自定义web-font实现数据防采集

    1. 数据混淆:自定义字体可以用来显示一些敏感数据,如订单号、验证码等。这些数据在源代码中以普通文本形式存在,但通过自定义字体渲染后,采集工具无法正确解析,从而达到防采集的目的。 2. 字体映射:可以创建一...

    web服务的建立和引用——模拟网上购物

    这个项目“web服务的建立和引用——模拟网上购物”旨在通过实例演示如何构建和使用Web服务来模拟一个简单的网上购物系统。在这个过程中,我们将重点讨论ASP.NET Web服务的使用,这是一种由微软提供的强大工具,用于...

    AjaxPro.DLL文件及使用方法 JS调用后台代码C#

    - **安全性**:确保对敏感数据进行加密,避免跨站脚本攻击(XSS)和跨站请求伪造(CSRF)。 - **异常处理**:在服务器端妥善处理异常,避免暴露过多的系统信息给用户。 总结,AjaxPro.DLL为ASP.NET开发者提供了一种简单...

    ASP.NET4高级程序设计(第4版) 3/3

    11.3 数据缓存 373 11.3.1 向缓存添加项目 373 11.3.2 简单的缓存测试 375 11.3.3 缓存优先级 376 11.3.4 使用数据源控件的缓存 376 11.4 缓存依赖 379 11.4.1 文件和缓存项目依赖 379 11.4.2 聚合...

    安卓开发-Android应用源码我要打车安卓手机打车项目.zip

    4. 内存管理:注意内存泄漏,避免对象冗余,合理使用软引用和弱引用。 五、安全性考虑 1. 数据加密:敏感信息如用户密码、订单详情等需进行加密传输和存储。 2. 权限管理:遵循最小权限原则,只申请必要的系统权限...

    Android编码规范.docx

    9. **数据加密**:对敏感数据进行加密,如使用AES、RSA等加密算法,保护用户隐私和应用安全。 **二、拓展 ADK (Android Development Kit)** 1. **动态加载方案**:实现动态加载可以减少应用安装包大小,如使用Dex...

    分享40条Android开发的优化建议

    5. **内存管理**:避免内存泄漏,及时释放不再使用的对象,合理使用软引用和弱引用。使用`Activity`的`onSaveInstanceState()`和`onRestoreInstanceState()`方法保存和恢复用户界面的状态。 6. **异步操作**:避免...

    sas ETL课件

    - **加密传输**:对敏感数据进行加密处理,防止中途截获。 - **备份与恢复计划**:制定详尽的数据备份方案,确保数据安全。 通过以上内容的学习,我们可以了解到SAS ETL不仅是一种工具,更是一种实现数据价值的重要...

Global site tag (gtag.js) - Google Analytics