带过期功能的map

1.自己定义

package com.aiggo.common.util;  
  
import java.util.Collection;  
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.Map;  
import java.util.Set;  
  
/** 
 *  
 * @Description: 带有效期map 简单实现 实现了基本的方法 
 * @author: qd-ankang 
 * @date: 2016-11-24 下午4:08:46 
 * @param <K> 
 * @param <V> 
 */  
public class ExpiryMap<K, V> extends HashMap<K, V>{  
  
    private static final long serialVersionUID = 1L;  
      
    /** 
     * default expiry time 2m 
     */  
    private long EXPIRY = 1000 * 60 * 2;  
      
    private HashMap<K, Long> expiryMap = new HashMap<>();  
      
    public ExpiryMap(){  
        super();  
    }  
    public ExpiryMap(long defaultExpiryTime){  
        this(1 << 4, defaultExpiryTime);  
    }  
    public ExpiryMap(int initialCapacity, long defaultExpiryTime){  
        super(initialCapacity);  
        this.EXPIRY = defaultExpiryTime;  
    }  
    public V put(K key, V value) {  
        expiryMap.put(key, System.currentTimeMillis() + EXPIRY);  
        return super.put(key, value);  
    }  
     public boolean containsKey(Object key) {  
         return !checkExpiry(key, true) && super.containsKey(key);  
     }  
    /** 
         * @param key 
         * @param value 
         * @param expiryTime 键值对有效期 毫秒 
         * @return 
     */  
    public V put(K key, V value, long expiryTime) {  
        expiryMap.put(key, System.currentTimeMillis() + expiryTime);  
        return super.put(key, value);  
    }  
    public int size() {  
        return entrySet().size();  
    }  
    public boolean isEmpty() {  
        return entrySet().size() == 0;  
    }  
    public boolean containsValue(Object value) {  
        if (value == null) return Boolean.FALSE;  
        Set<java.util.Map.Entry<K, V>> set = super.entrySet();  
        Iterator<java.util.Map.Entry<K, V>> iterator = set.iterator();  
        while (iterator.hasNext()) {  
            java.util.Map.Entry<K, V> entry = iterator.next();  
            if(value.equals(entry.getValue())){  
                if(checkExpiry(entry.getKey(), false)) {  
                    iterator.remove();  
                    return Boolean.FALSE;  
                }else return Boolean.TRUE;  
            }  
        }  
        return Boolean.FALSE;  
    }  
    public Collection<V> values() {  
          
        Collection<V> values = super.values();  
          
        if(values == null || values.size() < 1) return values;  
          
        Iterator<V> iterator = values.iterator();  
          
        while (iterator.hasNext()) {  
            V next = iterator.next();  
            if(!containsValue(next)) iterator.remove();  
        }  
        return values;  
    }  
    public V get(Object key) {  
        if (key == null)  
            return null;  
        if(checkExpiry(key, true))  
            return null;  
        return super.get(key);  
    }  
    /** 
     *  
         * @Description: 是否过期  
         * @param key 
         * @return null:不存在或key为null -1:过期  存在且没过期返回value 因为过期的不是实时删除,所以稍微有点作用 
     */  
    public Object isInvalid(Object key) {  
        if (key == null)  
            return null;  
        if(!expiryMap.containsKey(key)){  
            return null;  
        }  
        long expiryTime = expiryMap.get(key);  
          
        boolean flag = System.currentTimeMillis() > expiryTime;  
          
        if(flag){  
            super.remove(key);  
            expiryMap.remove(key);  
            return -1;  
        }  
        return super.get(key);  
    }  
    public void putAll(Map<? extends K, ? extends V> m) {  
         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())  
                expiryMap.put(e.getKey(), System.currentTimeMillis() + EXPIRY);  
         super.putAll(m);  
    }  
    public Set<Map.Entry<K,V>> entrySet() {  
        Set<java.util.Map.Entry<K, V>> set = super.entrySet();  
        Iterator<java.util.Map.Entry<K, V>> iterator = set.iterator();  
        while (iterator.hasNext()) {  
            java.util.Map.Entry<K, V> entry = iterator.next();  
            if(checkExpiry(entry.getKey(), false)) iterator.remove();  
        }  
          
        return set;  
    }  
    /** 
     *  
         * @Description: 是否过期  
         * @author: qd-ankang 
         * @date: 2016-11-24 下午4:05:02 
         * @param expiryTime true 过期 
         * @param isRemoveSuper true super删除 
         * @return 
     */  
    private boolean checkExpiry(Object key, boolean isRemoveSuper){  
          
        if(!expiryMap.containsKey(key)){  
            return Boolean.FALSE;  
        }  
        long expiryTime = expiryMap.get(key);  
          
        boolean flag = System.currentTimeMillis() > expiryTime;  
          
        if(flag){  
            if(isRemoveSuper)  
                super.remove(key);  
            expiryMap.remove(key);  
        }  
        return flag;  
    }  
    public static void main(String[] args) throws InterruptedException {  
          
        ExpiryMap<String, String> map = new ExpiryMap<>(10);  
        map.put("test", "ankang");  
        map.put("test1", "ankang");  
        map.put("test2", "ankang", 3000);  
        System.out.println("test1" + map.get("test"));  
        Thread.sleep(1000);  
        System.out.println("isInvalid:" + map.isInvalid("test"));  
        System.out.println("size:" + map.size());  
        System.out.println("size:" + ((HashMap<String, String>)map).size());  
        for (Map.Entry<String, String> m : map.entrySet()) {  
            System.out.println("isInvalid:" + map.isInvalid(m.getKey()));  
            map.containsKey(m.getKey());  
            System.out.println("key:" + m.getKey() + "     value:" + m.getValue());  
        }  
        System.out.println("test1" + map.get("test"));  
          
    }  
}  

ref:http://blog.csdn.net/u011534095/article/details/54091337

2.Java自带的LRU cache

package cn.lzrabbit.structure.lru;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by liuzhao on 14-5-15.
 */
public class LRUCache2<K, V> extends LinkedHashMap<K, V> {
    private final int MAX_CACHE_SIZE;

    public LRUCache2(int cacheSize) {
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        MAX_CACHE_SIZE = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_CACHE_SIZE;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<K, V> entry : entrySet()) {
            sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
        }
        return sb.toString();
    }
}
ref:http://www.cnblogs.com/lzrabbit/p/3734850.html

3.Google guava jar,也是最好用的,如下:

CacheBuilder作为LoadingCache 与 Cache实例的创建者,具有以下特征:

       1、自动载入键值至缓存;
       2、当缓存器溢出时,采用最近最少使用原则进行替换。
       3、过期规则可基于最后读写时间。
       4、设置键值引用级别。
       5、元素移出通知。
       6、缓存访问统计。
 
    示例:
       LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
                      .maximumSize(10)
                      .expireAfterWrite(10, TimeUnit.SECONDS)
                      .build(
                            new CacheLoader<String, Integer>() {
                                   public Integer load(String key) throws Exception {
                                          return loadKey(key);
                                   }
                            });
     例子中设定了缓存大小为10,写后10秒过期,命中失败时会通过load方法将查询键值加入缓存。
   
     缓存的移出策略主要有以下几种:
       1)基于缓存权重            
       LoadingCache<String, Integer> loadingCache = CacheBuilder.newBuilder()
                .maximumWeight(10)
                .weigher(new Weigher<String, Integer>() {
                    public int weigh(String k, Integer v) {
                        return v;    //v的权重设为其本身;
                    }
                })
                .recordStats()
                .build(
                        new CacheLoader<String, Integer>() {
                            public Integer load(String key) {
                                return num++;  //num初始值为1;
                            }
                        });
     System.out.println(loadingCache.get("a"));
            System.out.println(loadingCache.get("b"));
            System.out.println(loadingCache.get("c"));
            System.out.println(loadingCache.get("d"));
            System.out.println(loadingCache.get("a"));
        输出结果为1  2  3  4  1,当设置为maximumWeight(9)时,输出结果即为1  2  3  4  5,因为在get("d")时,权重值和已超过最大值9,a被移出,get("a")时,需重新加载,此时num为5。
    
    2)基于时间

       expireAfterAccess(long, TimeUnit):最后一次访问后的一段时间移出;

         expireAfterWrite(long, TimeUnit)  :最后一次写入后的一段时间移出;

    

    3 ) 基于引用

       键、值默认都是强引用,但键可设置弱引用(weakKeys),值可设置弱(weakValues)或软引用(softValues) 。

  强引用:如果一个对象具有强引用,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
  软引用:如果一个对象只具有软引用,如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
  弱引用:在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
    ref:
     通过recordStats()函数,还可开启缓存的访问统计,通过调用status()方法,返回包含统计信息的CacheStats对象,可以获取缓存的很多统计信息:hitCount(命中成功次数),missCount(命中失败次数),loadSuccessCount(载入成功次数),loadExceptionCount(载入失败次数),totalLoadTime(总载入时间),evictionCount(移除次数),requestCount() (访问次数),hitRate()(命中成功率),missRate()(命中失败率),loadCount()(载入次数)等。
ref:http://blog.csdn.net/desilting/article/details/11768773
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值