李琪的技术专栏 System Research

自定义缓存

2020-04-08
Clear Li

阅读:


自定义缓存

今天测试了照着网上的缓存写了一个简单的缓存功能。总体来说还是有很多感触的,以前很少用到多线程,这次才发现多线程也可以用到缓存上。。。。

  • 定义缓存

首先定义一个缓存类,很简单—–一个key一个value再加一个过期时间。代码如下


package com.clear;

/**
 * @author: CLEARLi
 * @date: 2020/4/5
 * @description 一般类
 */
public class Cache {
    private String key;
    private Object value;
    //有效期
    private Long timeout;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    public Long getTimeout() {
        return timeout;
    }

    public void setTimeout(Long timeout) {
        this.timeout = timeout;
    }
}


  • 创建缓存处理对象

缓存的主要思想,就是创建一个线程池,将要缓存的对象放入线程池中。使用定时线程定时检查缓存的对象是否超时。难点主要有两个。1.判断是否超时。2.线程池的创建和使用 。3.使用同步方法(容易被忽视)。

下面是代码

package com.clear;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author: CLEARLi
 * @date: 2020/4/5
 * @description 提供缓存api
 */
public class CacheManager {
    //存放缓存数据
    private Map<String ,Cache> cacheMap = new HashMap<>();
    public void put(String key, Object value) {
        put(key, value, null);
    }
    public synchronized void put(String key,Object value,Long timeout){
        Cache cache = new Cache();
        cache.setKey(key);
        cache.setValue(value);

        if (timeout!=null){
            cache.setTimeout(System.currentTimeMillis()+timeout);
            cacheMap.put(key,cache);
        }

    }
    public synchronized void del(String key){
        cacheMap.remove(key);
    }
    /**
     * 无建议(默认)
     * @description 使用key查询缓存
     * @author ClearLi
     * @date 2020/4/6 14:54
     * @param key
     * @return java.lang.Object
     */
    public synchronized Object get(String key){
        Cache cache = cacheMap.get(key);
        if (cache!=null){
            return cache.getValue();
        }
        return null;
    }
    public synchronized void remove(String key){
        System.out.println("调用删除");
        cacheMap.remove(key);
    }
    /**
     * 无建议(默认)
     * @description 定期检查有效期的值
     * @author ClearLi
     * @date 2020/4/6 15:04
     * @param
     * @return void
     */
    public synchronized void checkValidityData(){
        System.out.println("检查开始");
        for (String key : cacheMap.keySet()) {
            //System.out.println(key);
            Cache cache = cacheMap.get(key);
            if (cache==null){
                break;
            }
            //检查有效期
            //之前存放的毫秒数
            Long timeout = cache.getTimeout();
          //  System.out.println("之前的time"+timeout);
            //计算时间差
            Long currentTimeMillis = System.currentTimeMillis();
            if ((currentTimeMillis-timeout)>0){
                remove(key);
            }
        }

    }
    public static void main(String[] args) {
        CacheManager cacheManager = new CacheManager();
        cacheManager.put("userName","123",5000L);
        //开启一个线程定期刷新
        ScheduledExecutorService executorServicePool = Executors.newScheduledThreadPool(5);
        executorServicePool.schedule(new Runnable() {
            @Override
            public void run() {
                cacheManager.checkValidityData();
            }
        },5000, TimeUnit.MILLISECONDS);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(cacheManager.get("userName"));
    }


}

总体来说要考虑线程安全问题,和缓存判断失效两点问题。除了使用同步方法之外也可以使用线程安全的 Hashtable或者使用比较推荐的ConcurrentHashMap