java缓存——(五)LocalCache本地缓存分享

LocalCache本地缓存分享

前言

一、本地缓存应用场景

二、java本地缓存标准

三、java开源缓存框架

四、LocalCache实现

结束语

 

前言

本次分享探讨java平台的本地缓存,是指占用JVM的heap区域来缓冲存储数据的缓存组件。

 

一、本地缓存应用场景


localcache有着极大的性能优势:

1. 单机情况下适当使用localcache会使应用的性能得到很大的提升。

2. 集群环境下对于敏感性要求不高的数据可以使用localcache,只配置简单的失效机制来保证数据的相对一致性。

哪些数据可以存储到本地缓存?

1.访问频繁的数据;

2.静态基础数据(长时间内不变的数据);

3.相对静态数据(短时间内不变的数据)。

 

二、java本地缓存标准

Java缓存新标准(javax.cache),这个标准由JSR107所提出,已经被包含在Java EE 7中。

特性:

1.原子操作,跟java.util.ConcurrentMap类似

2.从缓存中读取

3.写入缓存

4.缓存事件监听器

5.数据统计

6.包含所有隔离(ioslation)级别的事务

7.缓存注解(annotations)

8.保存定义key和值类型的泛型缓存

9.引用保存(只适用于堆缓存)和值保存定义

                  

但目前应用不是很普遍。

 

三、java开源缓存框架

比较有名的本地缓存开源框架有:

1.EHCache

EHCache是一个纯java的在进程中的缓存,它具有以下特性:快速,简单,为Hibernate2.1充当可插入的缓存,最小的依赖性,全面的文档和测试。

BUG: 过期失效的缓存元素无法被GC掉,时间越长缓存越多,内存占用越大,导致内存泄漏的概率越大。

 

2.OSCache

OSCache有以下特点:缓存任何对象,你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。拥有全面的API--OSCache API给你全面的程序来控制所有的OSCache特性。永久缓存--缓存能随意的写入硬盘,因此允许昂贵的创建(expensive-to-create)数据来保持缓存,甚至能让应用重启。支持集群--集群缓存数据能被单个的进行参数配置,不需要修改代码。缓存记录的过期--你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(如果默认性能不需要时)。

 

3.JCache

Java缓存新标准(javax.cache)

 

4.cache4j

cache4j是一个有简单API与实现快速的Java对象缓存。它的特性包括:在内存中进行缓存,设计用于多线程环境,两种实现:同步与阻塞,多种缓存清除策略:LFU, LRU, FIFO,可使用强引用。

 

5.ShiftOne

ShiftOne Java Object Cache是一个执行一系列严格的对象缓存策略的Java lib,就像一个轻量级的配置缓存工作状态的框架。

 

6.WhirlyCache

Whirlycache是一个快速的、可配置的、存在于内存中的对象的缓存。

 

四、LocalCache实现

1、LocalCache简介

LocalCache是一个精简版本地缓存组件,有以下特点:

1.  有容量上限maxCapacity;

2.  缓存达到容量上限时基于LRU策略来移除缓存元素;

3.  缓存对象的生命周期(缓存失效时间)由调用方决定;

4.  缓存对象失效后,将会有定时清理线程来清理掉,不会导致内存泄漏。

5.  性能比Ehcache稍强。

 

2、总体设计

LocalCache总体设计:

1.  缓存元素 CacheElement;

2.  缓存容器 LRULinkedHashMap;

3.  缓存接口 Cache;

4.  缓存组件实现 LocalCache。

 

3、详细设计

1.  CacheElement设计

/**
 * 缓存元素
 *
 */
public class CacheElement {
    private Object key;
    private Object value;
    private long createTime;
    private long lifeTime;
    private int hitCount;
 
    public CacheElement() {
    }
 
    public CacheElement(Object key ,Object value) {
        this.key = key;
        this.value = value;
        this.createTime = System.currentTimeMillis();
    }
    
    public Object getKey() {
        return key;
    }
 
    public void setKey(Object key) {
        this.key = key;
    }
 
    public Object getValue() {
        hitCount++;
        return value;
    }
 
    public void setValue(Object value) {
        this.value = value;
    }
 
    public long getCreateTime() {
        return createTime;
    }
 
    public void setCreateTime(long createTime) {
        this.createTime = createTime;
    }
 
    public int getHitCount() {
        return hitCount;
    }
 
    public void setHitCount(int hitCount) {
        this.hitCount = hitCount;
    }
 
    public long getLifeTime() {
        return lifeTime;
    }
 
    public void setLifeTime(long lifeTime) {
        this.lifeTime = lifeTime;
    }
    
    public boolean isExpired() {
        boolean isExpired = System.currentTimeMillis() - getCreateTime() > getLifeTime();
        return isExpired;
    }
 
    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("[ key=").append(key).append(", isExpired=").append(isExpired())
            .append(", lifeTime=").append(lifeTime).append(", createTime=").append(createTime)
            .append(", hitCount=").append(hitCount)
            .append(", value=").append(value).append(" ]");
        return sb.toString();
    }
    
    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    public final int hashCode(){
        if(null == key){
            return "".hashCode();
        }
        return this.key.hashCode();
    }
    
    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public final boolean equals(Object object) {
        if ((object == null) || (!(object instanceof CacheElement))) {
            return false;
        }
 
        CacheElement element = (CacheElement) object;
        if ((this.key == null) || (element.getKey() == null)) {
            return false;
        }
 
        return this.key.equals(element.getKey());
    }
}

2.  LRULinkedHashMap实现

 

 
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 实现 LRU策略的 LinkedHashMap
 *
 * @param 
 * @param 
 */
public class LRULinkedHashMap extends LinkedHashMap  
{  
    protected static final long serialVersionUID = 2828675280716975892L;
    
    protected static final int DEFAULT_MAX_ENTRIES = 100;
    
    protected final int initialCapacity; 
    protected final int maxCapacity; 
    protected boolean enableRemoveEldestEntry = true;//是否允许自动移除比较旧的元素(添加元素时)
    
    protected static final float DEFAULT_LOAD_FACTOR = 0.8f;  
    protected final Lock lock = new ReentrantLock();  
 
    public LRULinkedHashMap(int initialCapacity)  
    {  
        this(initialCapacity, DEFAULT_MAX_ENTRIES);
    }
    
    public LRULinkedHashMap(int initialCapacity ,int maxCapacity)  
    {  
        //set accessOrder=true, LRU
        super(initialCapacity, DEFAULT_LOAD_FACTOR, true); 
        
        this.initialCapacity = initialCapacity; 
        this.maxCapacity = maxCapacity; 
    }
 
    /*
     *   (non-Javadoc)
     * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
     */
    protected boolean removeEldestEntry(java.util.Map.Entry eldest)  
    {  
        return enableRemoveEldestEntry && ( size() > maxCapacity );
    }  
 
    /*
     *   (non-Javadoc)
     * @see java.util.LinkedHashMap#get(java.lang.Object)
     */
    public V get(Object key)  
    {  
        try {  
            lock.lock();  
            return super.get(key);  
        }  
        finally {  
            lock.unlock();  
        }  
    }  
 
    /*
     *   (non-Javadoc)
     * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
     */
    public V put(K key, V value)  
    {  
        try {  
            lock.lock();  
            return super.put(key, value);  
        }  
        finally {  
            lock.unlock();  
        }  
    }  
    
    /*
     * (non-Javadoc)
     * @see java.util.HashMap#remove(java.lang.Object)
     */
    public V remove(Object key) {
        try {  
            lock.lock();
            return super.remove(key);
        }  
        finally {  
            lock.unlock();  
        }
    }
    
    /*
     * (non-Javadoc)
     * @see java.util.LinkedHashMap#clear()
     */
    public void clear() {
         try {  
             lock.lock();
             super.clear();
         }  
         finally {  
             lock.unlock();
         }
    }
    
    /*
     * (non-Javadoc)
     * @see java.util.HashMap#keySet()
     */
    public Set keySet() {
        try {  
            lock.lock();
            return super.keySet();
        }  
        finally {  
            lock.unlock();
        }
    }
    
    public boolean isEnableRemoveEldestEntry() {
        return enableRemoveEldestEntry;
    }
    public void setEnableRemoveEldestEntry(boolean enableRemoveEldestEntry) {
        this.enableRemoveEldestEntry = enableRemoveEldestEntry;
    }
    public int getInitialCapacity() {
        return initialCapacity;
    }
    public int getMaxCapacity() {
        return maxCapacity;
    }
}  

3.  Cache接口设计

 

/**
 * 缓存接口
 *
 */
public interface Cache {
    
    /**
     * 获取缓存
     * @param key
     * @return
     */
    public  T getCache(Object key);
    
    /**
     * 缓存对象
     * @param key
     * @param value
     * @param milliSecond 缓存生命周期(毫秒)
     */
    public void putCache(Object key, Object value ,Long milliSecond);
    
    /**
     * 缓存容器中是否包含 key 
     * @param key
     * @return
     */
    public boolean containsKey(Object key);
    
    /**
     * 缓存列表大小
     * @return
     */
    public int getSize();
    
    /**
     * 是否启用缓存
     */
    public boolean isEnabled();
    /**
     * 启用 或 停止
     * @param enable
     */
    public void setEnabled(boolean enabled);
    
    /**
     * 移除所有缓存
     */
    public void invalidateCaches();
    
    /**
     * 移除 指定key缓存
     * @param key
     */
    public void invalidateCache(Object key);
}

4.  LocalCache实现

 

import java.util.Date;
import java.util.Iterator;
import java.util.Random;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * 本地缓存组件
 */
public class LocalCache implements Cache{
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    private LRULinkedHashMap

结束语

开源或有BUG,入手需谨慎。 

原文:https://blog.csdn.net/u011683530/article/details/51029734

posted @ 2018-11-05 11:48  舞羊  阅读(16584)  评论(0编辑  收藏  举报