几种常见类型Cache的实现

        总述:Cache的实现有多种多样,基本上各个java开源框架都有自己的实现,而使用的最多的三种Cache类型是:FIFO(先入先出)、Random(随机)和LRU(最近最少使用)。上述分类主要是指Cache在存储已满时抛弃已有数据来缓存新添加的数据所选取的策略。Cache用来缓存数据的数据结构大多数是采用HashMap,以便快速存取。有些Cache的实现还设置有对象的缓存时间等,以期达到更细致的控制。

        在后面,提供了一个Cache的简略实现版本,抽象出一个简单的Cache接口,一个抽象的AbstractCache类,和上述三种类型Cache的具体实现,其中对于FIFO类型的Cache,提供了Array和List两种实现方式,相比较而言,List的效率更高。而LRU类型的Cache则是在List型FIFO的Cache基础之上再行封装的。时间复杂度上,Cache中缓存数据的读取主要依赖于HashMap的读取效率;写入缓存数据时,FIFO类型的List实现方式和Random类型为O(1),FIFO类型的Array实现方式为O(n),LRU类型最坏的时间复杂度为O(n)。空间复杂度上,LRU>list方式的FIFO>Array方式的FIFO=Random,不过List形式在内存分配上比Array形式更灵活。

Cache接口:

package com.lee.java.learning.cache;

/**
 * An interface defining the basic functions of a cache.
 * This cache can store the element by the key.
 * and also it can read the element from the cache by special key.
 * Except that, It provide methods to Get the size and capacity of
 * the cache, and judge a element exists in the cache or not.
 *
 * @version 1.0
 * @author lili06
 *
 */
public interface Cache {

	/**
	 * Add a element into cache by special key
	 * @param key
	 * @param value
	 */
	public void addElement(Object key, Object value);

	/**
	 * Read the element from the cache by special key
	 * @param key
	 * @return
	 */
	public Object getElement(Object key);

	/**
	 * If a element attached with the special key has been cached,
	 * this method return true, otherwise false.
	 * @param key
	 * @return
	 */
	public boolean isExist(Object key);

	/**
	 * Return the number of elements have been cached in the cache. not to be confused with
	 * the {@link #capacity()} which returns the number
	 * of elements that can be held in the cache at one time.
	 * @return the number of value object cached at one time
	 */
	public int size();

	/**
	 * Returns the maximum number of elements that can be cached at one time.
	 * <p>
	 * @return The maximum number of elements that can be cached at one time.
	 */
	public int capacity();

	/**
	 * Clear all the  cached elements.
	 */
	public void clear();

}

AbstractCache抽象类:

package com.lee.java.learning.cache;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;

public abstract class AbstractCache implements Cache, Serializable {

	private static final long serialVersionUID = 2046841211971587188L;

	public static final int DEFAULT_CAPACITY = 20;

	int size;
	int capacity;
	HashMap cacheMap;

	AbstractCache(int capacity) {
		size = 0;
		if(capacity <= 0) {
			throw new RuntimeException("the cache capacity must be a positive integer...");
		}
		this.capacity = capacity;
		cacheMap = new HashMap(capacity);
	}

	public abstract void addElement(Object key, Object value);

	public synchronized Object getElement(Object key) {
		Object obj = null;
		obj = cacheMap.get(key);
		if(obj != null) {
			return ((CacheEntity)obj).value;
		}

		return null;
	}

	public synchronized void clear() {
		cacheMap.clear();
		size = 0;
	}

	public synchronized boolean isExist(Object key) {
		if(getElement(key) != null) {
			return true;
		}

		return false;
	}

	public final synchronized int size() {
		return size;
	}

	public final synchronized int capacity() {
		return capacity;
	}

	public final synchronized boolean isFull() {
		return size == capacity;
	}

	static class CacheEntity {
		Object key;
		Object value;

		CacheEntity() {
			key = null;
			value = null;
		}
	}

}

CacheRandom实现类:

package com.lee.java.learning.cache;

import java.util.Random;

public class CacheRandom extends AbstractCache {

	private static final long serialVersionUID = -3906908597773607461L;

	private Random random;
	private RandomCacheEntity[] cache;

	public CacheRandom() {
		this(AbstractCache.DEFAULT_CAPACITY);
	}

	public CacheRandom(int capacity) {
		super(capacity);
		random = new Random(System.currentTimeMillis());
		cache = new RandomCacheEntity[capacity];
		for(int i=0; i<capacity; i++) {
			cache[i] = new RandomCacheEntity(i);
		}
	}

	@Override
	public synchronized void addElement(Object key, Object value) {
		int index = 0;
		Object obj = null;
		obj = cacheMap.get(key);

		if(obj != null) {
			RandomCacheEntity entity = (RandomCacheEntity)obj;
			entity.value = value;

			return;
		}

		if(!isFull()) {
			index = size;
			size++;
		}else {
			index = random.nextInt(capacity);
			cacheMap.remove(cache[index].key);
		}

		cache[index].key = key;
		cache[index].value = value;
		cacheMap.put(key, cache[index]);
	}

	@Override
	public synchronized void clear() {
		super.clear();
		for(int i=0; i<capacity; i++) {
			cache[i] = new RandomCacheEntity(i);
		}
	}

	static class RandomCacheEntity extends CacheEntity {
		int index;

		RandomCacheEntity(int index) {
			this.index = index;
		}
	}

}

ArrayCacheFIFO实现类:

package com.lee.java.learning.cache;

public class ArrayCacheFIFO extends AbstractCache {

	private static final long serialVersionUID = -4299736285228473989L;

	private int current = 0;
	private ArrayCacheEntity[] cache;

	public ArrayCacheFIFO() {
		this(AbstractCache.DEFAULT_CAPACITY);
	}

	public ArrayCacheFIFO(int capacity) {
		super(capacity);
		cache = new ArrayCacheEntity[capacity];
		for(int i=0; i<capacity; i++) {
			cache[i] = new ArrayCacheEntity(i);
		}
	}

	@Override
	public synchronized void addElement(Object key, Object value) {
		int index = current;
		Object obj = null;
		obj = getElement(key);

		if(obj != null) {
			ArrayCacheEntity entity = (ArrayCacheEntity)obj;
			updateOrder(entity, value);
			return;
		}

		if(!isFull()) {
			index = size;
			size++;
		}else {
			index = current;
			if(++current >= capacity) {
				current = 0;
			}

			cacheMap.remove(cache[index].key);
		}

		cache[index].key = key;
		cache[index].value = value;
		cacheMap.put(key, cache[index]);
	}

	private void updateOrder(ArrayCacheEntity entity, Object value) {

		int index = entity.index;
		Object key = entity.key;

		if(!isFull()) {
			for(int i=index; i<size-1; i++) {
				 cache[i].key = cache[i+1].key;
				 cache[i].value = cache[i+1].value;
			}
			cache[size-1].key = key;
			cache[size-1].value = value;

			for(int i=index; i<size; i++) {
				cacheMap.put(cache[i].key, cache[i]);
			}
		}else {
			if(index == current) {
				cache[current].value = value;
				cacheMap.put(cache[current].key, cache[current]);
				if(++current >= capacity) {
					current = 0;
				}
			}else if(index < current) {
				if((current-index)*2 <= capacity) {
					for(int i=index; i<current-1; i++) {
						cache[i].key = cache[i+1].key;
						cache[i].value = cache[i+1].value;
					}
					cache[current-1].key = key;
					cache[current-1].value = value;

					for(int i=index; i<current; i++) {
						cacheMap.put(cache[i].key, cache[i]);
					}
				}else {
					for(int i=index; i > 0; i--) {
						cache[i].key = cache[i-1].key;
						cache[i].value = cache[i-1].value;
					}
					cache[0].key = cache[capacity-1].key;
					cache[0].value = cache[capacity-1].value;
					for(int i=capacity-1; i>current; i--) {
						cache[i].key = cache[i-1].key;
						cache[i].value = cache[i-1].value;
					}
					cache[current].key = key;
					cache[current].value = value;
					int i = index, count = capacity - (current - index - 1);
					while(count-- > 0) {
						i = (i+capacity) % capacity;
						cacheMap.put(cache[i].key, cache[i]);
						i--;
					}

					current++;
				}
			}else {
				if((index-current+1)*2 <= capacity) {
					for(int i=index; i>current; i--) {
						cache[i].key = cache[i-1].key;
						cache[i].value = cache[i-1].value;
					}
					cache[current].key = key;
					cache[current].value = value;
					for(int i=current; i<=index; i++) {
						cacheMap.put(cache[i].key, cache[i]);
					}

					current++;
				}else {
					for(int i=index; i<capacity-1; i++) {
						cache[i].key = cache[i+1].key;
						cache[i].value = cache[i+1].value;
					}
					cache[capacity-1].key = cache[0].key;
					cache[capacity-1].value = cache[0].value;
					for(int i=0; i<current-1; i++) {
						cache[i].key = cache[i+1].key;
						cache[i].value = cache[i+1].value;
					}
					cache[current-1].key = key;
					cache[current-1].value = value;
					int i = index, count = capacity - (index-current);
					while(count-- > 0) {
						i %= capacity;
						cacheMap.put(cache[i].key, cache[i]);
						i++;
					}
				}
			}
		}

	}

	@Override
	public synchronized void clear() {
		for(int i=0; i<cache.length; i++) {
			cache[i] = new ArrayCacheEntity(i);
		}
	}

	static class ArrayCacheEntity extends CacheEntity {
		int index;

		ArrayCacheEntity(int index) {
			this.index = index;
		}
	}

}

ListCacheFIFO实现类:

package com.lee.java.learning.cache;

public class ListCacheFIFO extends AbstractCache {

	private static final long serialVersionUID = -1804440082070314369L;

	protected ListCacheEntity head;

	public ListCacheFIFO() {
		this(AbstractCache.DEFAULT_CAPACITY);
	}

	public ListCacheFIFO(int capacity) {
		super(capacity);
		head = new ListCacheEntity();
		head.pre = head.next = head;
	}

	@Override
	public synchronized void addElement(Object key, Object value) {
		Object obj = null;
		obj = cacheMap.get(key);

		if(obj != null) {
			ListCacheEntity entity = (ListCacheEntity)obj;
			entity.value = value;

			// update order
			entity.pre.next = entity.next;
			entity.next.pre = entity.pre;
			entity.pre = entity.next = null;
			moveToFront(entity, head);

			cacheMap.put(key, entity);

			return;
		}

		if(!isFull()) {
			size++;
		}else {
			ListCacheEntity temp = head.next;
			temp.pre.next = temp.next;
			temp.next.pre = temp.pre;
			temp.pre = temp.next = null;
			cacheMap.remove(temp.key);
		}

		ListCacheEntity entity = new ListCacheEntity();
		entity.key = key;
		entity.value = value;
		moveToFront(entity, head);

		cacheMap.put(key, entity);
	}

	protected void moveToFront(ListCacheEntity movedEntity, ListCacheEntity desEntity) {
		desEntity.pre.next = movedEntity;
		movedEntity.pre = desEntity.pre;
		desEntity.pre = movedEntity;
		movedEntity.next = desEntity;
	}

	@Override
	public synchronized void clear() {
		super.clear();
		head.pre = head.next = head;
	}

	static class ListCacheEntity extends CacheEntity {
		ListCacheEntity pre;
		ListCacheEntity next;

		ListCacheEntity() {
			pre = next = null;
		}
	}

}

CacheLRU实现类:

package com.lee.java.learning.cache;

import com.lee.java.learning.cache.ListCacheFIFO.ListCacheEntity;

public class CacheLRU extends ListCacheFIFO {

	private static final long serialVersionUID = 1122993622171221931L;

	public CacheLRU() {
		this(ListCacheFIFO.DEFAULT_CAPACITY);
	}

	public CacheLRU(int capacity) {
		super(capacity);
		head = new CacheLRUEntity();
		head.pre = head.next = head;
	}

	@Override
	public synchronized void addElement(Object key, Object value) {
		Object obj = null;
		obj = cacheMap.get(key);

		if(obj != null) {
			CacheLRUEntity entity = (CacheLRUEntity)obj;
			entity.value = value;
			entity.count++;

			// update order
			CacheLRUEntity it = (CacheLRUEntity) entity.next;
			while(it != head && it.count <= entity.count) {
				it = (CacheLRUEntity)it.next;
			}
			if(it == entity.next) {
				// do nothing
			}else {
				entity.pre.next = entity.next;
				entity.next.pre = entity.pre;
				entity.pre = entity.next = null;
				moveToFront(entity, it);
			}

			cacheMap.put(key, entity);

			return;
		}

		if(!isFull()) {
			size++;
		}else {
			ListCacheEntity temp = head.next;
			temp.pre.next = temp.next;
			temp.next.pre = temp.pre;
			temp.pre = temp.next = null;
			cacheMap.remove(temp.key);
		}

		CacheLRUEntity entity = new CacheLRUEntity();
		entity.count = 1;
		entity.key = key;
		entity.value = value;

		CacheLRUEntity it = (CacheLRUEntity) head.next;
		while(it != head && it.count <= entity.count) {
			it = (CacheLRUEntity)it.next;
		}
		moveToFront(entity, it);

		cacheMap.put(key, entity);
	}

	@Override
	public synchronized Object getElement(Object key) {
		Object obj = null;
		obj = cacheMap.get(key);
		if(obj != null) {
			CacheLRUEntity entity = (CacheLRUEntity)obj;
			entity.count++;

			// update order
			CacheLRUEntity it = (CacheLRUEntity) entity.next;
			while(it != head && it.count <= entity.count) {
				it = (CacheLRUEntity)it.next;
			}
			if(it == entity.next) {
				// do nothing
			}else {
				entity.pre.next = entity.next;
				entity.next.pre = entity.pre;
				entity.pre = entity.next = null;
				moveToFront(entity, it);
			}

			return entity.value;
		}

		return null;
	}

	static class CacheLRUEntity extends ListCacheEntity {
		int count;

		CacheLRUEntity() {
			count = 0;
		}
	}

}

 

备注:具体的代码包可在http://download.csdn.net/source/3543311下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值