如果程序经常需要使用相同的不可变类实例,则应该考虑缓存者在不可变类的实例。毕竟重复创建相同的对象没有太大的意义,而且加大系统开销。
缓存是软件设计中一个非常有用的模式,缓存的实现方式有很多种,不同的实现方式可能存在较大的性能差别。但是,盲目乱用缓存也会导致系统性能下降,缓存的对象会占用系统内存,所以缓存一个重复使用概率不大的实例,就弊大于利。
下面这个例子是根据java疯狂讲义里的例子改写的,改进了覆盖机制,加入了多线程支持。
但是我不太确定所加的同步锁是否完全正确,待以后修改
package test;
class CacheImmutale {
private static int MAX_SIZE = 10;
// 使用数组来缓存已有的实例
private static CacheImmutale[] cache = new CacheImmutale[MAX_SIZE];
//记录缓存实例在缓存中的位置,cache[pos-1]是最新缓存的实例
private static int pos = 0;
private static int pushLock = 0;
private final String name;
//记录缓存里每个对象被使用的次数,被创建时算第一次。
private int useTime = 1;
private CacheImmutale(String name){
this.name = name;
}
public String getName(){
return name;
}
//这里有个问题,希望没有写操作时,cache读取不被锁,但是多线程写操作时又不冲突,我不知道这样处理是否有遗漏,也不知道会不会造成死锁问题,
public static CacheImmutale getCacheImmutale(String name){
//遍历已缓存的对象
for(int i = 0; i < MAX_SIZE; i++){
//如果已有相同的实例,则直接返回该缓存的实例
if(pushLock==0){
if(cache[i]!=null&&cache[i].getName().equals(name)){
return cache[i];
}
}else{
synchronized(cache){
if(cache[i]!=null&&cache[i].getName().equals(name)){
return cache[i];
}
}
}
}
return pushCacheImmutaleIntoCache(name);
}
private static synchronized CacheImmutale pushCacheImmutaleIntoCache(String name){
//如果缓存池已满
CacheImmutale tmpCacheImmutale;
pushLock ++;
synchronized(cache){
if(!(pos == MAX_SIZE)){
//这个的意思是,先把值存入cache[pos],pos再加1
cache[pos++] = new CacheImmutale(name);
tmpCacheImmutale = cache[pos-1];
}else{
//把缓存的第一个对象覆盖,即把刚刚生成的对象放在缓存池的最开始的位置
//这里,如果按照优先把使用的次数最少的替换掉,其次把最早的替换掉的替换策略,应该更好。
//之所以不在调用时顺便排序,主要是因为调用的次数应该比溢出的次数多很多
int tmpMinUseTime = cache[0].useTime;
int tmpIndex = 0;
//不从0开始是因为觉得浪费,不过从1开始,导致了MAX_SIZE要大于等于1
for(int i = 1; i < MAX_SIZE; i++){
if(tmpMinUseTime>cache[i].useTime){
tmpIndex = i;
}
}
cache[tmpIndex] = new CacheImmutale(name);
tmpCacheImmutale = cache[tmpIndex];
}
}
pushLock --;
return tmpCacheImmutale;
}
@Override
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj != null && obj.getClass() == CacheImmutale.class){
CacheImmutale ci = (CacheImmutale)obj;
return name.equals(ci.getName());
}
return false;
}
public int hashCode(){
return name.hashCode();
}
}
public class CacheImmutaleTest{
public static void main(String[] args){
CacheImmutale c1 = CacheImmutale.getCacheImmutale("hello");
CacheImmutale c2 = CacheImmutale.getCacheImmutale("hello");
System.out.println(c1==c2);
}
}