闲来无事,用Java的软引用写了一个山寨的缓存
闲来无事,用Java的软引用写了一个山寨的缓存
博客分类:
- java基础
众所周知java中的引用分为 StrongReference、SoftReference、WeakReference、PhantomReference。这几种引用有不同那个的 使用场景,平时我们用的最频繁的也就是StrongReference也就是说形如之这样的引用:
Object obj = new Object();
这种引用就是所谓的强引用,如果此对象没有引用指向它,并且活着的线程无法访问到它(针对垃圾孤岛而言),那么他才会被回收,如果该对象被强引用指向,并且内存被耗尽,抛出OOM垃圾收集器也不会回收该对象。
而对于SoftReference而言它被GC回收的条件就没 那么严格了,如果一个对象当前最强的引用是软引用,并且JVM的内存充足,垃圾回收器是不会回收的该对象的。只有在内存比较吃紧的情况下GC才会回收被软 引用指向的对象,从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。今天我就自己写一个玩玩。
- 代码如下:
/*
@author blackbeans
*
* 背景知识:
* 而对于SoftReference而言它被GC回收的条件就没那么严格了,
* 如果一个对象当前最强的引用是软引用,并且JVM的内存充足,
* 垃圾回收器是不会回收的该对象的。只有在内存比较吃紧的情况下GC才会回收被软引用指向的对象,
* 从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。今天我就自己写一个玩玩。
*
* 而对于SoftReference而言它被GC回收的条件就没那么严格了,
* 如果一个对象当前最强的引用是软引用,并且JVM的内存充足,
* 垃圾回收器是不会回收的该对象的。
* 只有在内存比较吃紧的情况下GC才会回收被软引用指向的对象,
* 从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。
*
*/
public class ReferenceCache<K, T> { private HashMap<K, InnerReference<K, T>> cachedReference = new HashMap<K, InnerReference<K, T>>(1024); private final ReferenceQueue<T> referenceQueue; private final ObjectNotFoundHandler<K, T> existsHandler; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 缓存中取不到时的处理器 接口
*
* @author blackbeans
*
* @param <K>
* @param <T>
*/
public static interface ObjectNotFoundHandler<K, T> { public T queryAndCached(K key);
} /**
* 默认缓存中取不到时的处理器 实现类
*
* @author blackbeans
*
* @param <K>
* @param <T>
*/
private static class DefaultObjectNotFoundHandler<K, T> implements ObjectNotFoundHandler<K, T> { @Override
public T queryAndCached(K key) {
return null;
} } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 继承软引用
*
* @param <K>
* @param <T>
*/
private static class InnerReference<K, T> extends SoftReference<T> { private final K key; public InnerReference(K key, T reference, ReferenceQueue<T> queue) {
super(reference, queue);
this.key = key;
} public K getKey() {
return this.key;
}
} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 本类构造方法
*
* @param handler
*/
public ReferenceCache(ObjectNotFoundHandler<K, T> handler) {
this.referenceQueue = new ReferenceQueue<T>();
this.existsHandler = handler == null ? new DefaultObjectNotFoundHandler<K, T>() : handler;
} public ReferenceCache() {
this(null);
} /**
* 清除给定key的缓存
*
* @param key
*/
@SuppressWarnings("unchecked")
private void cleanReference(K key) {
//优先检查key对应软引用的对象是否被回收
if (this.cachedReference.containsKey(key) && this.cachedReference.get(key).get() == null) {
this.cachedReference.remove(key);
}
T obj = null;
//如果当前Key对应的软引用的对象被回收则移除该Key
Reference<? extends T> reference = null;
while ((reference = this.referenceQueue.poll()) != null) {
obj = reference.get();
if (obj == null) {
this.cachedReference.remove(((InnerReference<K, T>) reference).getKey());
}
}
} /**
* 把需要缓存的数据放入缓存池
*
* @param key
* @param reference
*/
public void put(K key, T reference) {//cachedReference
/**
* 清除被软引用的对象并已经被回收的reference
*/
cleanReference(key);
if (!this.cachedReference.containsKey(key)) {
this.cachedReference.put(key, new InnerReference<K, T>(key, reference, this.referenceQueue));
}
} /**
* 获取缓存池内的换成对象
*
* @param key
* @return
*/
public T get(K key) {//getReference T obj = null; if (this.cachedReference.containsKey(key)) {
obj = this.cachedReference.get(key).get();
} if (null == obj) {
/**
* 软引用指向的对象被回收,并缓存该软引用
*/
obj = this.existsHandler.queryAndCached(key);
this.put(key, obj);
return obj;
}
return obj; } /**
* 清空所有缓存
*/
public void clearALLObject() {
this.cachedReference.clear();
System.gc();
} public boolean containsKey(Object key) {
return cachedReference.containsKey(key);
} public static void main(String[] args) {
ReferenceCache cache = new ReferenceCache();
cache.put("11", new SiteBean());
System.out.println(cache.get("11"));
cache.cleanReference("11");
cache.clearALLObject();
}
在整个实现中通过将对象的引用放入我定义的一个 key->软引用map中,然后每次从cache中获取对象时,首先通过key去查询map获得对象的软引用,若存在则通过软引用去尝试获取对象, 若不存在,软引用指向的对象被回收,那么我们就回去调用内置的handler,重新生成一个对象,并cache该对象的软引用。
在我的实现中我为用户提供了一个当对象被回收时的处理handler,企图来指导用户通过这个handler来重新构造对象,缓存对象,灵活性还是挺大的。
不足之处就是,如果软引用的缓存能用LRU策略更完美了,再为 LRU提供一个Processor,用于用户自定义LRU策略。其实很简单只要将HashMap换成LinkedHashMap去实现 removeEldest方法,并在方法中调用自定义的LRU处理器就OK了。
为了减少开销,我在每次cache的时候才去清理已经失效的软引用。也许有人会问为啥有个ReferenceQueue呢?其实是这样的,在软引用所引用 的对象被回收以后,试想想对象软引用的对象是被回收了,但是你又引入了另一个对象SoftReference,带走一个难道还要再留下一个,所以不会的, 软引用对象被回收后,这个软引用本身被添加到了这个queue,等待回收。通过便利这个queue获取软引用来一出map中过期的软引用。
至此,该说的也都说了,不该说的也说了,结尾很突兀,敬请见谅!
转载:http://blackbeans.iteye.com/blog/1039464
闲来无事,用Java的软引用写了一个山寨的缓存的更多相关文章
- 关于Java的软引用及弱引用
概念介绍 1 Reference 描述一个对象的引用.其内部维持一个queue引用,用于跟踪对象的回收情况,当对象被回收时将当前reference引用入队 2 SoftRef ...
- 【java基础】随手写的一个日期计算,新手可以看看
随手写的一个例子, 只是练习下自己的代码布局以及思路.. 1. 先写下简单的测试 2. 根据常用的不用修改的变量抽取出来, 作为常量(常量的命名可能有点不规范,谅解~) 3. 方法的作用不一样, 抽取 ...
- java环境搭建和写出一个Helloworld
一.安装环境和配置环境变量(必要环节) 安装java并配置环境变量 :在"系统变量"中设置3项属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击 ...
- Java反射结合JDBC写的一个通用DAO
以前写反射只是用在了与设计模式的结合上,并没有考虑到反射可以与DAO结合.也是一个偶然的机会,被正在上培训的老师点到这个问题,才考虑到这个可能性,于是上网参考各种代码,然后自己动手开发了一个通用DAO ...
- 分享自己写的一个.net方法缓存源码
在服务器性能优化中,我们更多的是要考虑到缓存的使用,分享一个自己编写的方法缓存的框架,使用非常方便.话不多说,先上使用例子: 1.定义要使用缓存的类及方法: public class Example ...
- Java四大引用详解:强引用、软引用、弱引用、虚引用
面试官考察Java引用会问到强引用.弱引用.软引用.虚引用,具体有什么区别?本篇单独来详解 @mikechen Java引用 从JDK 1.2版本开始,对象的引用被划分为4种级别,从而使程序能更加灵活 ...
- Java 对象引用方式 —— 强引用、软引用、弱引用和虚引用
Java中负责内存回收的是JVM.通过JVM回收内存,我们不需要像使用C语音开发那样操心内存的使用,但是正因为不用操心内存的时候,也会导致在内存回收方面存在不够灵活的问题.为了解决内存操作不灵活的问题 ...
- java强引用、软引用、弱引用、虚引用
前言概述 在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象.这就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走 ...
- 【转载】 Java 7之基础 - 强引用、弱引用、软引用、虚引用
原文地址:http://blog.csdn.net/mazhimazh/article/details/19752475 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一 ...
随机推荐
- 经典趣味24点游戏程序设计(python)
一.游戏玩法介绍: 24点游戏是儿时玩的主要益智类游戏之一,玩法为:从一副扑克中抽取4张牌,对4张牌使用加减乘除中的任何方法,使计算结果为24.例如,2,3,4,6,通过( ( ( 4 + 6 ) - ...
- 自动化测试: sikuli,一个基于界面图像的gui测试框架
http://www.sikuli.org/ license: MIT script language: Python 下面是他的一个hello world的例子,看看也挺有意思的. 开源的世界里有很 ...
- Jenkins进阶系列之——05FTP publisher plugin插件
说明:这个插件可以将构建的产物(例如:Jar)发布到FTP中去. 官方说明:FTP publisher plugin 安装步骤: 系统管理→管理插件→可选插件→Artifact Uploaders→F ...
- html5 canvas 粒子特效
不知不觉就已经好久没写过博客了,自从七月正式毕业后,离开了实习了将近九个月的老东家,进了鼠厂后,做的事都是比较传统的前端活,之前在tpy的时候只管做移动h5的特效以及小游戏,再加上实习所以时间比较充裕 ...
- .NET领域最为流行的IOC框架之一Autofac
一.前言 Autofac是.NET领域最为流行的IOC框架之一,微软的Orchad开源程序使用的就是Autofac,Nopcommerce开源程序也是用的Autofac. Orchad和Nopcomm ...
- 从Lumia退役看为什么WP走向没落
前段时间决定将自己用了三年多的Lumia 800正式退役,这是我用的时间最长的手机,虽然系统上有缺陷,但是好不妨碍他成为我最有感情的一部手机.由于之前是WinPhone 开发者的关系,这部手机是微软送 ...
- PHP 系列:PHP Web 开发基础
PHP是动态类型的Web开发的脚本语言,PHP以页面文件作为加载和运行的单元,PHP现在有了Composer作为开发包管理. 1.使用Composer管理依赖 自从.NET开发用了Nuget管理程序集 ...
- 服务器网站报错:由于扩展配置问题无法提供您请求的页面,请添加MIME映射,针对mp4,flv文件类型无法打开。
确保IIS正常 服务器增加mp4格式的MIME 类型映射设置的具体步骤是: “开始” > “控制面板” > “管理工具” >“Internet 信息服务(IIS管理器)”,“MIME ...
- 第三章:Javascript类型、值和变量。
计算机程序的运行需要对值(value)比如数字3.14或者文本"hello world"进行操作,在编程语言中,能够表示并操作的值的类型叫做数据类型(type),编程语言最基本的特 ...
- .NET Core 工具从 project.json 移动到基于 MSBuild 的项目后的使用
.NET Core 从preview 4 开始弃用project.json 可以从这下载最新版本: https://github.com/dotnet/cli 使用VS2017 RC新建.net co ...