总述: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下载