缓存(cache)
缓存也是为了提高系统性能而开辟的内存空间。缓存主要作用是暂存数据处理结果,并提供下次访问使用。在很多场合,数据的处理和数据的获取会非常费时,当对这个数据的请求量很大时,频繁的数据处理会耗尽CPU资源,缓存的作用就是将这些来之不易的数据处理结果暂存起来,当有其他线程或者客户端需要查询相同的数据资源时,可以省略对这些数据的处理流程,而直接从缓存中获取处理结构,并立即返回处理组件,以此提高系统的响应时间。
缓存的使用非常普遍,比如目前流行的几种浏览器都会在本地缓存远程的页面,从而减少远程HTTP的访问次数,加快网页的加载速度。又比如在服务端的系统开发中,设计人员可以为一些核心的API加上缓存,从而提高系统的整体性能。
最为简单的缓存可以直接使用HashMap来实现,当然这样做会遇到很多问题,何时应该清理无效的数据,如何防止缓存数据过多而导致内存溢出等。一个稍好的替代方案是直接使用WeakHashMap,它使用弱引用维护一张哈希表,从而避免了潜在的内存溢出问题,但是作为专业的缓存,它的功能也略有不足。
幸运的是,目前有很多基于java的缓存框架,比如EHCache、OSCache和JBossCache等。
EHCache出自Hibernate,是Hibernate框架默认的数据解决方案。
OSCache是由OpenSymphony,它可以用于缓存任何对象,甚至是缓存部分JSP页面,或者HTTP请求。
JBossCache是由JBoss开发,可用于JBoss集群间,数据共享的缓存框架。
以EHCache缓存为例,介绍一下缓存的使用方法:
diskStore
diskStore元素:制定一个路径,当EHCache把数据写到硬盘上的时候,
会把数据写到该目录下。user.home - 用户主目录;user.dir - 用户当前工作目录;
java.io.tmpdir - 默认临时文件路径。
defaultCache
设定缓存的默认数据过期策略。
cache
设定具体的命名缓存的数据过期策略。
name
缓存名称。通常为缓存对象的类名;
maxElementsInMemory
设置基于内存的缓存可存放对象的最大数目;
maxElementOnDisk
设置基于硬盘的缓存可存放对象的最大数目;
eternal
如果为true,表示对象永远不会过期,此时会忽略tiemToldleSeconds和timeToLiveSeconds属性
默认为false。
timeToldleSeconds
设置允许对象处于空闲状态的最长时间,以秒为单位。
当对象最近一次被访问后,如果处于空闲状态的时间超过了
timeToldleSeconds属性值,这个对象就会过期。
当对象过期,EHCache将把它从缓存中清空。只有当eternal属性为false.
该属性才有效。如果该属性的值为0,那么就表示该对象可以无限期地存于缓存中。
即缓存被创建后,最后一次访问时间到缓存失效之时,两者之间的间隔,单位为秒(s)
timeToLiveSeconds
必须大于timeToldleSeconds属性,才有意义;
当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,
这个对象就会过期,EHCache将把它从缓存中清除;
即缓存自创建日期起能够存活的最长时间,单位为秒(s)
overflowToDisk
如果为true,表示当基于内存的缓存中的对象数目达到了maxElementsInMemory界限后
会把溢出的对象写到基于硬盘的缓存中。
注意,如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行(也就是序列化);
memoryStoreEvictionPolicy
缓存对象清除策略。
有三种:
FIFO:first in first out
先进先出。
LFU:Less Frequently Used
一直以来最少被使用策略,缓存元素有一个hit属性,hit(命中)值最小的将会被清除出缓存。
LRU:least Recenly used
最近最少被使用,缓存的元素有一个时间戳,当缓存的容量满了,
而又需要腾出地方来缓存新的元素的时候,
那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
diskSpoolBufferSizeMB
写入磁盘的缓冲区大小。
由于diskSpoolBufferSizeMB在内部实际是以字节为单位,
所以最大值是Integer的最大值即2047.99…M,反正不到2G。
所以如果配置的超过2G,将会导致diskSpoolBufferSizeMB为负数,
在put时ehcache误以为磁盘缓存队列已满,每次都执行都会阻塞。
maxElementsOnDisk
在DiskStore(磁盘存储)中的最大对象数量,如为0,则没有限制
diskPersistent
是否disk store在虚拟机启动时持久化。默认为false
diskExpiryThreadIntervalSeconds
Ehcache后台线程专门做Ellment失效监测以及清除工作。
此值不宜设置过低,否则会导致清理线程占用大量CPU资源。
默认值是120秒。
clearOnFlush
当调用flush()是否清除缓存,默认是。
maxEntriesLocalHeap
堆内存中最大缓存对象数,0没有限制
ehcache-setting.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
<diskStore path="D://cui" />
<!-- 设定缓存的默认数据过期策略 -->
<defaultCache maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120" />
<cache name="cache1" maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/>
<cache name="cache2" maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/>
</ehcache>
EHCache使用简单,可以向使用HashMap一样使用它,为了方便使用,我们将EHCahce进行封装。
EHCache工具类:
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
public class EHCacheUtil {
//首先初始化EHCache
private static final String path="ehcache-setting.xml";
private URL url;
private CacheManager manager;
private static EHCacheUtil ehCache;
private EHCacheUtil(String path) {
url=getClass().getResource(path);
manager=CacheManager.create(url);
}
public static EHCacheUtil getInstance() {
if(ehCache==null) {
ehCache=new EHCacheUtil(path);
}
return ehCache;
}
public void put(String cacheName,String key,Object value) {
Cache cache=manager.getCache(cacheName);
Element element=new Element(key, value);
cache.put(element);
}
public Object get(String cacheName,String key) {
Cache cache=manager.getCache(cacheName);
Element element=cache.get(key);
return element==null?null:element.getObjectValue();
}
public Cache get(String cacheName) {
return manager.getCache(cacheName);
}
public void remove(String cacheName, String key) {
Cache cache = manager.getCache(cacheName);
cache.remove(key);
}
}
使用:
public class Demo {
public static void main(String[] args) throws Exception {
EHCacheUtil ehUtil=EHCacheUtil.getInstance();
ehUtil.put("cache1", "name", "cuixiansheng");
String name=(String) ehUtil.get("cache1", "name");
System.out.print(name);
}
}
结果:
cuixiansheng
maven依赖:
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-nop -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.25</version>
<scope>test</scope>