Java 3クラスによるメモリキャッシュの実装

9390 ワード

redisでやろうとしたが、redisのlistがタイムアウト設定をサポートしていないことに気づき、
だからjavaで簡単なキャッシュを書きました.redisのような操作で、全部で3つのクラスしかありません.
プロジェクトのアドレス:https://github.com/newpanjing/group-cache.git
プロジェクト名:group-cache
簡単なメモリキャッシュは実現して、groupの概念を実現して、1つのgroupの中で秩序ある集合で、集合はkey-value expireを支持してredis listの不足を補います
全部で3つのクラスがあります.
GroupCacheFactoryファクトリGroupの取得
Groupグループ、複数のkeyとvalueを格納
CacheEntityはエンティティをキャッシュし、すべてのキャッシュされたデータはCacheEntityをキャリアとしてGroupに格納されます.
テストコード:
package com.qikenet.cache;

import java.util.Random;

public class CacheTest {

public static void main(String[] args) {
    /**
     *   :
     *    ,   redis、memcached          ,  key-value   
     *       ,   key-value        
     *  list    , redis ,list       ,  list            :
     *  abc
     *      1
     *      2
     *      3
     * 
     *  GroupCache          :
     * abc
     *  a 1 10
     *  b 2 5
     *  c 3 1
     *    :a  key,1  value,10    10 ,                  
     */

    //      ,        
    GroupCacheFactory factory=new GroupCacheFactory();
    //     
    Group group1=factory.group("group1");
    group1.push("a", 123);//      
    group1.push("b", 321, 10);//  10 

    //        
    System.out.println("group 1    b       :"+group1.ttl("b"));

    //       
    System.out.println("a    :"+group1.exist("a"));
    System.out.println("c    :"+group1.exist("c"));

    //     key
    System.out.println("group1 keys:"+group1.getKeys());

    //     value
    System.out.println("group1 values:"+group1.getValues());

    //  key   
    System.out.println("  a  :"+group1.getValue("a"));


    //     ,      100,     1000,   group       
    Group group2=factory.group("group2",100);

    //  push       ,    
    for(int i=0;i<101;i++){
        group2.push(String.valueOf(i), i, new Random().nextInt(10));
    }
    //          
    System.out.println("group2  :"+group2.size());

    //         
    group2.expire("2", 100);

    //      
    group2.delete("3");
    System.out.println("group        :"+group2.size());

    //  group    
    System.out.println("group2  :"+group2.getCapacity());

    System.out.println(group2.getKeys());

}
}

具体的なコード:
キャッシュファクトリ:
package com.qikenet.cache;

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

/**
 *          ,  group  ,
* group ,
* key-value expire redis list * * @author panjing * @date 2016 8 6 9:27:22 * @project qikenet-group-cache */ public class GroupCacheFactory { // private Map container; public GroupCacheFactory() { container = new LinkedHashMap(); } /** * , , null * * @param key * @return */ public Group group(String key, int capacity) { Group group = null; Object entry = container.get(key); if (entry != null) { group = (Group) entry; } else { group = new Group(capacity); container.put(key, group); } return group; } /** * , , 1000 * * @param key * @return */ public Group group(String key) { return this.group(key, 1000); } }

キャッシュグループ:
package com.qikenet.cache;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;

/**
 *    ,        
 * 
 * @author panjing
 * @date 2016 8 6    9:33:34
 * @project qikenet-group-cache
 * @param 
 */
public class Group {

	private ArrayBlockingQueue queue;//     

	private Integer capacity;

	public Group(int capacity) {
		queue = new ArrayBlockingQueue(capacity);
		this.capacity = capacity;
	}

	/**
	 *    
	 * 
	 * @param object
	 * @param second
	 */
	public void push(String key, Object object, int second) {

		//     ,
		queue.offer(new CacheEntity(key, object, System.currentTimeMillis(), second, this));
	}

	/**
	 *    
	 * 
	 * @param object
	 */
	public void push(String key, Object object) {

		push(key, object, 0);
	}

	/**
	 *         
	 * 
	 * @return
	 */
	public Object poll() {

		CacheEntity entity = queue.poll();
		//        ,  null
		if (!entity.isExpire()) {
			return null;
		}
		return entity.getValue();
	}

	/**
	 *            
	 * 
	 * @return
	 */
	public Object rPoll() {

		CacheEntity entity = queue.poll();
		//        ,  null
		if (!entity.isExpire()) {
			return null;
		}
		Object object = entity.getValue();
		queue.offer(entity);
		return object;
	}

	/**
	 *   key         
	 * 
	 * @param key
	 * @return
	 */
	private CacheEntity find(String key) {

		synchronized (queue) {
			Iterator iterator = queue.iterator();
			while (iterator.hasNext()) {
				CacheEntity entity = iterator.next();
				if (key.equals(entity.getKey())) {
					return entity;
				}
			}
			return null;
		}
	}

	/**
	 *   key
	 * 
	 * @param key
	 */
	public void delete(String key) {

		synchronized (queue) {
			CacheEntity entity = find(key);
			if (entity != null) {
				queue.remove(entity);
			}
		}
	}

	/**
	 *   key  
	 * 
	 * @param key
	 * @return
	 */
	public Object getValue(String key) {

		CacheEntity entity = find(key);
		if (entity != null && entity.isExpire()) {
			return entity.getValue();
		}

		return null;
	}

	/**
	 *          
	 * 
	 * @return
	 */
	private List getCacheEntitys() {

		List keys = new ArrayList();
		Iterator iterator = queue.iterator();
		while (iterator.hasNext()) {
			CacheEntity cacheEntity = iterator.next();
			if (cacheEntity.isExpire()) {
				keys.add(cacheEntity);
			}
		}
		return keys;
	}

	/**
	 *   key  
	 * 
	 * @return
	 */
	public List getKeys() {

		List keys = new ArrayList();
		List caches = getCacheEntitys();
		for (CacheEntity cacheEntity : caches) {
			keys.add(cacheEntity.getKey());
		}
		return keys;
	}

	/**
	 *      
	 * 
	 * @return
	 */
	public List getValues() {

		List values = new ArrayList();
		List caches = getCacheEntitys();
		for (CacheEntity cacheEntity : caches) {
			values.add(cacheEntity.getValue());
		}
		return values;
	}

	/**
	 *         ,-1   ,0     
	 * 
	 * @param key
	 * @return
	 */
	public int ttl(String key) {

		CacheEntity entity = find(key);
		if (entity != null) {
			return entity.ttl();
		}
		return -1;
	}

	/**
	 *        
	 * 
	 * @return
	 */
	public Object peek() {

		CacheEntity entity = queue.peek();
		if (entity != null) {
			return entity.getValue();
		}
		return null;
	}

	/**
	 *         
	 * 
	 * @param key
	 * @param second
	 */
	public void expire(String key, int second) {

		CacheEntity entity = find(key);
		if (entity != null) {
			entity.setTimestamp(System.currentTimeMillis());
			entity.setExpire(second);
		}
	}

	/**
	 *   key    
	 * 
	 * @param key
	 * @return
	 */
	public boolean exist(String key) {

		return find(key) != null;
	}

	/**
	 *        
	 * 
	 * @return
	 */
	public boolean isEmpty() {

		return queue.isEmpty();
	}

	/**
	 *          
	 * 
	 * @return
	 */
	public int size() {

		return getCacheEntitys().size();
	}

	/**
	 *     
	 * 
	 * @return
	 */
	public Integer getCapacity() {

		return capacity;
	}
}
キャッシュエンティティ:
package com.qikenet.cache;

import java.io.Serializable;

/**
 *     
 * 
 * @author panjing
 * @date 2016 8 6    9:33:25
 * @project qikenet-group-cache
 */
public class CacheEntity implements Serializable {

	private static final long serialVersionUID = 2082223810638865724L;

	private String key; // key

	private Object value;//  

	private Long timestamp;//           ,           

	private int expire = 0; //       

	private Group group;//   

	public CacheEntity(String key, Object value, Long timestamp, int expire, Group group) {
		super();
		this.key = key;
		this.value = value;
		this.timestamp = timestamp;
		this.expire = expire;
		this.group = group;
	}

	public void setTimestamp(Long timestamp) {

		this.timestamp = timestamp;
	}

	public Long getTimestamp() {

		return timestamp;
	}

	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 int getExpire() {

		return expire;
	}

	public void setExpire(int expire) {

		this.expire = expire;
	}

	/**
	 *       
	 * 
	 * @return
	 */
	public int ttl() {

		if (this.expire == 0) {
			return this.expire;
		}
		return this.expire - getTime();
	}
	
	/**
	 *               
	 * @return
	 */
	private int getTime() {

		if (this.expire == 0) {
			return this.expire;
		}
		Long current = System.currentTimeMillis();
		Long value = current - this.timestamp;
		return (int) (value / 1000) + 1;
	}

	/**
	 *     
	 * 
	 * @return
	 */
	public boolean isExpire() {

		if (this.expire == 0) {
			return true;
		}
		if (getTime() > this.expire) {
			//       
			group.delete(key);
			return false;
		}
		return true;
	}
}