欢迎您的访问
专注架构,Java,数据结构算法,Python技术分享

Java实现Key带有效期的Map

工作需要实现key带有效期的功能,小项目直接上redis有点重,就想着重写一个Map来实现该功能,网上参考下另外一位大佬的代码进行了改动,增加了closeMap()方法,保证进程能正常退出。

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * created by wangpengfei
 * created in 2020/8/7
 * Description: 带有效期的Map,每个key存入该map时,都需要设置key的有效期!
 * 当超期后,该key失效,此外,该map加入了一个定时器,每间隔一段时间,就自动扫描该map一次,清除失效的key
 * 需要进程退出需要提前调用map的closeMap()方法来关闭定时器。
 */
public class ExpiryMap <KVimplements Map<KV{

    private boolean isRefresh = false;
    private Timer timer = null;
    private static ConcurrentHashMap workMap = new ConcurrentHashMap();
    private static ConcurrentHashMap<Object, Long> expiryMap = new ConcurrentHashMap<>();

    public ExpiryMap() {
        super();
    }

    public ExpiryMap(boolean isRefresh) {
        this.isRefresh = isRefresh;
        startClearKey();
    }

    public void closeMap(){
        timer.cancel();
    }
    /**
     * 定时清除失效key
     */
    public void startClearKey(){

        int interval = 60;//间隔时间,单位:分
        int threshold = 10000;//map的容量阈值,达到该值后,将较频繁的执行key扫描工作!

        timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            int i = 0;
            @Override
            public void run() {
                boolean isRun = ++i % interval == 0 || expiryMap.keySet().size() > threshold;
                if (isRun) {
                    removeInValidKeys();
                }
            }
        };
        timer.schedule(timerTask, 60*100060*1000); //延迟一分钟启动个,以后每个一分钟启动一次
    }

    private static void removeInValidKeys(){
        expiryMap.keySet().forEach(key->{
            if(expiryMap.get(key) < System.currentTimeMillis()){
                expiryMap.remove(key);
                workMap.remove(key);
            }
        });
        System.gc();
    }

    /**
     * put方法,需要设置key 的有效期!单位为:毫秒
     * @param key
     * @param value
     * @param expiry key的有效期,单位:毫秒
     * @return
     */
    public V put(K key, V value, long expiry) {
        if (!containsKey(key) || isRefresh) {//更新value,只有需要刷新时间时才需要操作expiryMap
            expiryMap.put(key, System.currentTimeMillis() + expiry);
        }
        workMap.put(key, value);
        return value;
    }

    @Override
    public int size() {
        return keySet().size();
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public boolean containsKey(Object key) {
        if (key!=null &&expiryMap.containsKey(key)) {
            boolean flag = expiryMap.get(key) > System.currentTimeMillis();
            return flag;
        }
        return false;
    }

    @Override
    public boolean containsValue(Object value) {
        Collection values = workMap.values();
        if(values!=null){
            return values.contains(value);
        }
        return false;
    }

    @Override
    public V get(Object key) {
        if (containsKey(key)) {
            return (V) workMap.get(key);
        }
        return null;
    }

    @Deprecated
    @Override
    public V put(K key, V value) {
        throw new RuntimeException("此方法已废弃!请加上key失效时间");
    }

    @Override
    public V remove(Object key) {
        boolean containKey=containsKey(key);
        expiryMap.remove(key);
        if(containKey){
            return (V) workMap.remove(key);
        }else{
            return null;
        }

    }

    @Deprecated
    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        throw new RuntimeException("此方法已废弃!");
    }

    @Override
    public void clear() {
        expiryMap.clear();
        workMap.clear();
    }

    @Override
    public Set<K> keySet() {
        removeInValidKeys();
        return workMap.keySet();
    }

    @Override
    public Collection<V> values() {
        removeInValidKeys();
        return workMap.values();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        removeInValidKeys();
        return workMap.entrySet();
    }
    public static void main(String[] args) {
        //ExpiryMap emap=new ExpiryMap();
        ExpiryMap emap=new ExpiryMap(true);
        emap.put("key1","value1",2*1000);
        emap.put("key2","value2",5*1000);
        emap.put("key3","value3",15*1000);
        System.out.println(emap.size());
        try {
            Thread.sleep(10*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(emap.size());
        System.out.println(emap.keySet());
        System.out.println(emap.values());
        System.out.println(emap.entrySet());
        emap.put("key4","value4",8*1000);
        System.out.println(emap.size());
        try {
            Thread.sleep(10*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(emap.size());
        System.out.println(emap.keySet());
        System.out.println(emap.values());
        System.out.println(emap.entrySet());

        emap.closeMap();
    }
}

 

赞(0) 打赏
版权归原创作者所有,任何形式转载请联系作者;码农code之路 » Java实现Key带有效期的Map

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏