Cache的作用:
在并發(fā)環(huán)境中減少重復(fù)性的對(duì)后臺(tái)的調(diào)用,從而提高運(yùn)行效率。
Cache必須要做到的:
1.保證Cache中的數(shù)據(jù)與后臺(tái)系統(tǒng)數(shù)據(jù)的一致性。
2.Cache必須要減少訪問(wèn)后臺(tái)的操作以提高效率。
如果不能同時(shí)做到以上兩點(diǎn),則Cache失去了意義。
Cache的基本操作:
Read(Get):按鍵值從Cache中取得想要的數(shù)據(jù);
Write(Put):將鍵值對(duì)放到Cache中;
Reset(RemoveAll):清除Cache中的原有數(shù)據(jù);
IsExist(has):判斷某鍵在Cache中是否存在。
Cache中對(duì)數(shù)據(jù)的保護(hù):
因?yàn)镃ache多用于多線程環(huán)境中,需要對(duì)數(shù)據(jù)進(jìn)行保護(hù);
同步方法,同步塊能起到保護(hù)的作用,但是效率不高;
讀寫(xiě)鎖也能起到保護(hù)的左右,而且效率較高。
Cache數(shù)據(jù)的時(shí)效性:
使用過(guò)期數(shù)據(jù)是危險(xiǎn)的,我們必須確保取出的數(shù)據(jù)的時(shí)效性;
當(dāng)放入數(shù)據(jù)時(shí)我們可以記錄放入的時(shí)間,這樣取出時(shí)就能得到它,然后與當(dāng)前時(shí)間進(jìn)行比較,如果小于一定間隔則可以認(rèn)為數(shù)據(jù)沒(méi)有時(shí)效。間隔一般可以設(shè)置為后臺(tái)數(shù)據(jù)被更新間隔的平均時(shí)間的一半。
Cache的設(shè)計(jì):
1.Data類,用以存儲(chǔ)數(shù)據(jù)和放入時(shí)間:
import java.io.Serializable;
import java.util.Date;
public class Data implements Serializable{
private static final long serialVersionUID = 8596587790584575734L;
private byte[] value;
private Date date;
public Data(byte[] value,Date date){
this.value=value;
this.date=date;
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
this.value = value;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
2.ReadWriteLock,用以在并發(fā)環(huán)境中保護(hù)數(shù)據(jù):
/**
* Read-write Lock Class
*
* @author heyang
* @time Sep 23, 2011,3:55:55 PM
*/
public class ReadWriteLock {
private boolean isRead;
private boolean isWrite;
/**
* Add Read Lock
*/
public synchronized void readLock(){
while(isWrite){
try{
wait();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
isRead=true;
}
/**
* Unlock the read-lock
*/
public synchronized void readUnlock(){
isRead=false;
notifyAll();
}
/**
* Add write lock
*/
public synchronized void writeLock(){
while(isRead){
try{
wait();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
while(isWrite){
try{
wait();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
isWrite=true;
}
/**
* Unlock the write-lock
*/
public synchronized void writeUnlock(){
isWrite=false;
notifyAll();
}
}
3.AbstractCacheMap,用以提供Cache的接口和操作:
import java.util.Date;
/**
* Parent class of InnerCacheMap & OutterCacheMap
*
* @author heyang
* @time Sep 23, 2011,4:00:45 PM
*/
public abstract class AbstractCacheMap {
private static final int Time_Limit_300 = 300;
// Read-Write lock,for protecting the cacheMap in the Multi-thread environment
private ReadWriteLock lock;
/**
* Contructor
*/
public AbstractCacheMap() {
lock = new ReadWriteLock();
}
/**
* Put key-value pair into cacheMap
* It can be called by any class
* @param key
* @param value
* @throws Exception
*/
public void writeData(String key,byte[] value) throws Exception{
try {
lock.writeLock();
set(key,new Data(value,new Date()));
} finally {
lock.writeUnlock();
}
}
/**
* Put key-value pair into cacheMap,force child-class to implement.
* It only can be called by child-class
* @param key
* @param value
*/
protected abstract void set(String key,Data data) throws Exception;
/**
* Get value by it's key
* It can be called by any class
*
* @param key
* @return
* @throws Exception
*/
public byte[] readData(String key) throws Exception{
try {
lock.readLock();
Data data=get(key);
return data.getValue();
} finally {
lock.readUnlock();
}
}
/**
* Get value by it's key,force child-class to implement.
* It only can be called by child-class
*
* @param key
* @return
* @throws Exception
*/
protected abstract Data get(String key) throws Exception;
/**
* Judge the existence of a key
* It can be called by any class
*
* @param key
* @return
* @throws Exception
*/
public boolean containsKey(String key) throws Exception{
try {
lock.readLock();
if(contains(key)){
Data data=get(key);
return isexceedTimeLimit(data.getDate());
}
return false;
} finally {
lock.readUnlock();
}
}
/**
* Judge the existence of a key,force child-class to implement.
* It only can be called by child-class
*
* @param key
* @return
* @throws Exception
*/
protected abstract boolean contains(String key) throws Exception;
/**
* Remove a key-value pair from cacheMap by it's key
* It can be called by any class
*
* @param key
* @throws Exception
*/
public void removeData(String key) throws Exception{
try {
lock.writeLock();
remove(key);
} finally {
lock.writeUnlock();
}
}
/**
* Remove a key-value pair from cacheMap by it's key
* It only can be called by child-class
*
* @param key
* @return
* @throws Exception
*/
protected abstract void remove(String key) throws Exception;
/**
* Remove all data in the cacheMap
* It can be called by any class
*
* @throws Exception
*/
public void removeAllData() throws Exception{
try {
lock.writeLock();
removeAll();
} finally {
lock.writeUnlock();
}
}
/**
* Remove all data in the cacheMap
* It only can be called by child-class
*
* @param key
* @return
* @throws Exception
*/
protected abstract void removeAll() throws Exception;
/**
* Judge the date whether exceed the time limit
*
* @param date
* @return
*/
private static boolean isexceedTimeLimit(Date date){
long diff = (new Date()).getTime() - date.getTime();
return diff<Time_Limit_300;
}
}
4.InnerCacheMap,用HashMap作為實(shí)際內(nèi)存空間的Cache實(shí)現(xiàn)類:
import java.util.HashMap;
import java.util.Map;
import cachemap.base.AbstractCacheMap;
import cachemap.base.Data;
/**
* CacheMap used local HashMap
*
* @author heyang
* @time Sep 23, 2011,3:48:17 PM
*/
public class InnerCacheMap extends AbstractCacheMap{
// essential storage
private Map<String,Data> map;
/**
* Contructor
*/
public InnerCacheMap(){
super();
map=new HashMap<String,Data>();
}
@Override
protected Data get(String key) throws Exception {
return map.get(key);
}
@Override
protected void set(String key, Data value) throws Exception {
map.put(key, value);
}
@Override
protected boolean contains(String key) throws Exception {
return map.containsKey(key);
}
@Override
protected void remove(String key) throws Exception {
map.remove(key);
}
@Override
protected void removeAll() throws Exception {
map.clear();
}
}
5.CacheMapSetter類,用于向Cache中異步寫(xiě)入數(shù)據(jù):
import cachemap.base.AbstractCacheMap;
/**
* CacheMapSetter
* It's use is to set a key-value pair into cacheMap
*
* @author heyang
* @time Sep 26, 2011,10:11:36 AM
*/
public final class CacheMapSetter implements Runnable{
// The reference to the cacheMap
private AbstractCacheMap cacheMap;
private String key;
private byte[] value;
/**
* Constuctor
* @param cacheMap
* @param key
* @param value
*/
public CacheMapSetter(AbstractCacheMap cacheMap,String key,byte[] value){
this.cacheMap=cacheMap;
this.key=key;
this.value=value;
new Thread(this).start();
}
@Override
public void run(){
try{
cacheMap.writeData(key, value);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
6.使用示例:
// Get key
String key=getKey(inputEnv);
// Get operation
String operation=getOperation(inputEnv);
if("READ".equalsIgnoreCase(operation)){
if(cacheMap.containsKey(key)){
byte[] value=cacheMap.readData(key);
// TODO:
.....
}else{
// TODO:
...
}
}else if("WRITE".equalsIgnoreCase(operation)){
if(cacheMap.containsKey(key)){
cacheMap.removeData(key);
}
byte[] value=getValue(outputEnv);
new CacheMapSetter(cacheMap,key, value);
// TODO:
....
}else if("REMOVEALL".equalsIgnoreCase(operation)){
cacheMap.removeAllData();
// TODO:
....
}else{
throw new Exception("Unknown Operation:"+operation);
}
以上類的代碼下載: