java实现一个本地缓存

缓存接口定义:

import java.util.Iterator;

/**
 * @author lijiaxing
 * @Title: GatewayCache
 * @ProjectName gateway
 * @date 2019/12/4下午4:11
 * @Description: 缓存接口
 */
public interface GatewayCache<K, V> {
    /**
     * 将数据加入到缓存,数据存活时长不做限制
     * @param key
     * @param value
     */
    void put(K key, V value);

    /**
     *  将数据加入到缓存,数据存活时长为ttl,单位为毫秒
     * @param key
     * @param value
     * @param ttl
     */
    void put(K key, V value,long ttl);

    /**
     *  从缓存中获取数据
     * @param key
     * @return
     */
    V get(K key);

    /**
     * 从缓存中删除指定的数据
     * @param key
     */
    void remove(K key);

    /**
     * 获取当前缓存中数据的总数
     * @return
     */
    int size();

    /**
     *
     * @return
     */
    long sizeof();

    /**
     * 判断当前缓存是否为空
     * @return
     */
    boolean isEmpty();

    /**
     * 判断缓存是否存在
     * @param key
     * @return
     */
    boolean containsKey(K key);

    /**
     * 清空所有缓存
     * @return 被删除数据的个数
     */
    int clear();

    /**
     * 获取缓存Map的迭代器
     * @return
     */
    Iterator getIterator();

    /**
     * 根据不同的策略清除缓存中的数据
     */
    int reduce(long size);

}

抽象类:

import org.apache.lucene.util.RamUsageEstimator;
import org.aspectj.util.SoftHashMap;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author lijiaxing
 * @Title: AbstractGatewayCache
 * @ProjectName gateway
 * @date 2019/12/4下午4:24
 * @Description: 抽象缓存类
 */
public abstract class AbstractGatewayCache<K, V> implements GatewayCache<K, V> {

    /**
     * 缓存,使用软引用,会在内存不够时将缓存回收
     */
    public Map<K, CacheDataWrapper<K, V>> cache = new SoftHashMap<>();
    /**
     * 缓存锁
     */
    protected static final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
    /**
     * 读锁
     */
    protected static final ReentrantReadWriteLock.ReadLock readLock = cacheLock.readLock();
    /**
     * 写锁
     */
    protected static final ReentrantReadWriteLock.WriteLock writeLock = cacheLock.writeLock();
    /**
     * 缓存在堆中占用的最大内存,默认为200MB
     */
    protected long maxCacheSize = RamUsageEstimator.ONE_MB * 200;
    /**
     * 缓存当前所占用的内存大小
     */
    protected long currentCacheSize = RamUsageEstimator.sizeOf(this.cache);

    @Override
    public void put(K key, V value) {
        writeLock.lock();
        try {
            doPut(key, value, -1);
        } finally {
            writeLock.unlock();
        }
    }

    @Override
    public void put(K key, V value, long ttl) {
        writeLock.lock();
        try {
            doPut(key, value, ttl);
        } finally {
            writeLock.unlock();
        }
    }

    private void doPut(K key, V value, long ttl) {
        long current = System.currentTimeMillis();
        CacheDataWrapper dataWrapper = new CacheDataWrapper(value, ttl, current, 0);
        increaseCurrentCacheSize(dataWrapper);
        this.cache.put(key, dataWrapper);
    }

    /**
     *
     * @param obj
     * @return
     */
    private long increaseCurrentCacheSize(Object obj) {
        long size = RamUsageEstimator.sizeOf(obj);
        while (this.sizeof() + size >= this.maxCacheSize) {
            //使用具体的策略清除缓存数据
            reduce(size);
        }
        /**
         *  75%
         */
        if ((this.sizeof() + size) / this.maxCacheSize > 0.75) {
            //异步执行扫描任务,将已过期的数据从缓存中剔除
        }
        return currentCacheSize += size;
    }


    @Override
    public V get(K key) {
        readLock.lock();
        CacheDataWrapper<K, V> dataWrapper = null;
        try {
            dataWrapper = this.cache.get(key);
            if (dataWrapper == null) {
                return null;
            }
        } finally {
            readLock.unlock();
        }
        if (dataWrapper.isExpired()) {
            this.remove(key);
        }
        return dataWrapper.get(Boolean.TRUE);
    }

    @Override
    public void remove(K key) {
        writeLock.lock();
        try {
            this.cache.remove(key);
        } finally {
            writeLock.unlock();
        }
    }

    @Override
    public int size() {
        readLock.lock();
        try {
            return this.cache.size();
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public long sizeof() {
        readLock.lock();
        try {
            return RamUsageEstimator.sizeOf(this.cache);
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public boolean isEmpty() {
        readLock.lock();
        try {
            return this.cache.isEmpty();
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public boolean containsKey(K key) {
        readLock.lock();
        try {
            CacheDataWrapper<K, V> dataWrapper = this.cache.get(key);
            if (dataWrapper == null) {
                return Boolean.FALSE;
            }

            if (dataWrapper.isExpired()) {
                remove(key);
            }
        } finally {
            readLock.unlock();
        }
        return Boolean.TRUE;
    }

    @Override
    public int clear() {
        writeLock.lock();
        int total = cache.size();
        try {
            cache.clear();
        } finally {
            writeLock.unlock();
        }
        return total;
    }

    @Override
    public Iterator<Map.Entry<K, CacheDataWrapper<K, V>>> getIterator() {
        return this.cache.entrySet().iterator();
    }

    @Override
    public abstract int reduce(long size);

    @Override
    public String toString() {
        String s = "GatewayCache{\n";
        Iterator<Map.Entry<K, CacheDataWrapper<K, V>>> iterator = getIterator();
        while (iterator.hasNext()) {
            Map.Entry<K, CacheDataWrapper<K, V>> next = iterator.next();
            K key = next.getKey();
            CacheDataWrapper<K, V> value = next.getValue();
            s = s + key + "->" + value + "\n";
        }
        return s + "}";
    }
}

缓存对象:

public class CacheDataWrapper<K, V> {
    /**
     * 缓存的值
     */
    private V value;
    /**
     * 缓存对象存活时间
     *   默认为 0
     *   已过期则为-1
     */
    private long ttl;
    /**
     * 上次访问的时间(时间戳)
     */
    private long lastAccessTime;
    /**
     * 访问次数
     */
    private int accessCount;


    public CacheDataWrapper(V value, long ttl, long lastAccessTime, Integer accessCount) {
        this.value = value;
        this.ttl = ttl;
        this.lastAccessTime = lastAccessTime;
        this.accessCount = accessCount;
    }

    /**
     * 判断当前缓存对象是否过期
     *
     * @return
     */
    public boolean isExpired() {
        Boolean expired = Boolean.FALSE;
        if (ttl > 0) {
            expired = System.currentTimeMillis() - lastAccessTime > ttl;
        }
        return expired;
    }

    /**
     * @return
     */
    public V get() {
        return value;
    }

    /**
     * @param updateExpiringTime 是否刷新过期时间
     * @return
     */
    public V get(Boolean updateExpiringTime) {
        if(updateExpiringTime){
            this.lastAccessTime = System.currentTimeMillis();
        }
        accessCount++;
        return get();
    }

    public int getAccessCount() {
        return accessCount;
    }

    @Override
    public String toString() {
        return "CacheDataWrapper{" +
                "value=" + value +
                ", ttl=" + ttl +
                ", lastAccessTime=" + lastAccessTime +
                ", accessCount=" + accessCount +
                '}';
    }
}

具体实现:

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author lijiaxing
 * @Title: GatewayLocalCache
 * @ProjectName gateway
 * @date 2019/12/5下午3:20
 * @Description: 缓存淘汰策略使用LFU(Least Frequently Used) ,即最近最少使用
 * <p>
 * 如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。
 * 因此,当空间满时,最小频率访问的数据最先被淘汰。
 */
public class GatewayLocalCache<K, V> extends AbstractGatewayCache<K, V> {

    /**
     * @param maxCacheSize 缓存最大所占用的内存空间
     *                     <p>
     *                     n * RamUsageEstimator.ONE_KB; 表示nK大小
     *                     n * RamUsageEstimator.ONE_MB; 表示nM大小
     *                     n * RamUsageEstimator.ONE_GB; 表示nG大小
     */
    public GatewayLocalCache(long maxCacheSize) {
        super.maxCacheSize = maxCacheSize;
    }

    /**
     * 使用缓存最大所占用的内存空间的默认值,即500MB
     */
    public GatewayLocalCache() {

    }

    private int minAccessCount = 0;

    @Override
    public int reduce(long size) {
        int count = 0;
        Iterator<Map.Entry<K, CacheDataWrapper<K, V>>> iterator = super.getIterator();
        while (iterator.hasNext()) {
            Map.Entry<K, CacheDataWrapper<K, V>> next = iterator.next();
            CacheDataWrapper<K, V> dataWrapper = next.getValue();
            boolean expired = dataWrapper.isExpired();
            if (expired) {
                super.remove(next.getKey());
                count++;
            }

            if (minAccessCount == 0 || dataWrapper.getAccessCount() < minAccessCount)
                minAccessCount = dataWrapper.getAccessCount();
        }

        /**
         * 有过期数据被处理的情况不执行下面代码
         *
         * 遍历缓存中的数据,使缓存中每一个CacheDataWrapper的accessCount值都减minAccessCount
         * 目的是保证公平
         */
        if (super.sizeof() + size > super.maxCacheSize) {
            Set<Map.Entry<K, CacheDataWrapper<K, V>>> entries = super.cache.entrySet();
            for (Map.Entry<K, CacheDataWrapper<K, V>> entry : entries) {
                CacheDataWrapper<K, V> dataWrapper = entry.getValue();
                if (dataWrapper.getAccessCount() - minAccessCount <= 0) {
                    writeLock.lock();
                    try {
                        this.cache.remove(entry.getKey());
                    } finally {
                        writeLock.unlock();
                    }
                    count++;
                }
            }
        }
        return count;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值