Cache 之自我实现磁盘缓存

17 篇文章 0 订阅


磁盘缓存简述

书接http://blog.csdn.net/supingemail/article/details/46008661 ,接着说,其实呀,这个磁盘缓存,无非就是将存放到内存中的东东,存放到磁盘上去,

然后在内存中给个对应的映射关系,标明有哪些缓存对象。

       

实现思路 

         1. cache 地方是确定的,大小是需要管理的,移除机制需要设定的 ?

       2. 如何计算放入的object 的大小,这个是个非常关键的地方,要是不知道放入的object的大小,那还怎么玩呀、是不是?

       3. cache 的管理:cache的移除,cache 的放入,cache的获取.

       4.如何写入写出,这个要比写内存复杂多了,因为有些类型是比较难搞的,所以这个也是重点。


具体实现

 内存计算大小,除过 http://blog.csdn.net/supingemail/article/details/46008661  中的SizeOf ,还有如下工具类供使用


可以验证下,还是有些区别的。
public class ObjBytesSizeUtil {

private ObjBytesSizeUtil() {

}


static final Hashtable pSizes;

static {
pSizes = new Hashtable();
pSizes.put(Boolean.TYPE, new Integer(1));
pSizes.put(Byte.TYPE, new Integer(1));
pSizes.put(Void.TYPE, new Integer(1));

pSizes.put(Character.TYPE, new Integer(2));
pSizes.put(Short.TYPE, new Integer(2));

pSizes.put(Integer.TYPE, new Integer(4));
pSizes.put(Float.TYPE, new Integer(4));

pSizes.put(Long.TYPE, new Integer(8));
pSizes.put(Double.TYPE, new Integer(8));
}


private static final class Root {

}


private static void sizeof(Object obj, IdentityHashMap known, Hashtable types) {
Stack stack = new Stack();
stack.push(new Root().getClass());
stack.push(obj);
int rounds = 0;
while (!stack.empty()) {
Object o = stack.pop();
Object parentClass = stack.pop();
known.put(o, o);
rounds += 1;
int size = 8; 
Class oc = o.getClass();
if (oc.isArray()) {
size += 8;
int alen = Array.getLength(o);
Class ec = oc.getComponentType();
Integer l = (Integer) pSizes.get(ec);
if (l != null) {
size = size + alen * l.intValue();
} else {
size = size + 4 * alen;
Object[] oa = (Object[]) o;
for (int i = 0; i < alen; i++) {
Object child = oa[i];
if (child != null && !known.containsKey(child)) {
stack.push(parentClass);
stack.push(child);
}
}
}
} else {
Class c = oc;
while (c != null) {
Field[] fields = c.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
if (Modifier.isStatic(f.getModifiers())) {
continue;
}
Class fc = f.getType();
Integer l = (Integer) pSizes.get(fc);
if (l != null) {
size += l.longValue();
continue;
}
size += 4;
Object child;
f.setAccessible(true);
try {
child = f.get(o);
if (child == null || known.containsKey(child)) {
continue;
}
stack.push(oc); 
stack.push(child);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
c = c.getSuperclass();
}
}


Map parents = (Map) types.get(oc);
if (parents == null) {
types.put(oc, parents = new HashMap());
}
Pair p = (Pair) parents.get(parentClass);
if (p == null) {
p = new Pair();
parents.put(parentClass, p);
}
p.count += 1;
p.size += size;
}
}


public static Hashtable sizeof(Object o) {
Hashtable types = new Hashtable();
sizeof(o, new IdentityHashMap(), types);
return types;
}


public static long printTypes(Hashtable types) {
Enumeration it = types.keys();
long count = 0, size = 0;
while (it.hasMoreElements()) {
Class c = (Class) it.nextElement();
Map parents = (Map) types.get(c);
Iterator pit = parents.keySet().iterator();
while (pit.hasNext()) {
Class parenClass = (Class) pit.next();
Pair p = (Pair) parents.get(parenClass);
String pname = parenClass.getName();
count += p.count;
size += p.size;
}
}
return size;
}

public static class Pair {

public int count;

public long size;
}



public static void main(String[] args) {
Object object = new Object();  //8
boolean tag = false;
int numtest = 1;  //8+4
double doubletest = 5.23;  //8+8
String[] strs = new String[]{""}; //
String str = "我是中国人,我爱我的祖国!"; 
System.out.println(printTypes(sizeof(object)));
System.out.println(printTypes(sizeof(tag)));
System.out.println(printTypes(sizeof(numtest)));
System.out.println(printTypes(sizeof(doubletest)));
System.out.println(printTypes(sizeof(strs)));
System.out.println(printTypes(sizeof(str)));

}
}


主要的DiskCache类


使用时候,如下会介绍:
public class DiskCache {


private static Map<String, File> diskCache = new ConcurrentHashMap<String, File>();

private static Map<String, Integer> usedMap = new HashMap<String, Integer>();

private static LinkedList<String> putOrder = new LinkedList<String>();

private static long Total_Disk_Size = 10*1024*1024*1024 ;

private static long Change_Disk_Size = 0L ;

private static String Cache_Path = "java.io.tmpdir";

private static String Remove_Strategy = "FIFO";

private Properties props = null;

private static DiskCache instance;

public static DiskCache getInstance() {
if (instance == null) {
synchronized (DiskCache.class) {
if (instance == null) {
instance = new DiskCache();
}
}
}
return instance;
}


private DiskCache() {
String cacheSize = getProperty("cache.disk.size", "");
if (cacheSize!=null && !cacheSize.equals("")) {
Total_Disk_Size = Integer.parseInt(cacheSize)*1024*1024*1024;
}
Cache_Path = getProperty("cache.path.disk", Cache_Path);
File file = new File(Cache_Path);
if (!file.exists()) {
file.mkdirs();
}
Remove_Strategy = getProperty("cache.remove.tag", Remove_Strategy);
}


public Object get(String key) {
try {
if (diskCache.get(key) != null) {
File file = diskCache.get(key);
InputStream is  =  new FileInputStream(file);
DataInputStream dis = new DataInputStream(is);
String className = dis.readUTF();
WriteableObject wObject = (WriteableObject)Class.forName(className).newInstance();
wObject.read(is);
if (usedMap.containsKey(key)) {
usedMap.put(key, usedMap.get(key)+1);
}else {
usedMap.put(key, 1);
}
return wObject;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}


public boolean put(String key, Object object) {
long objByteSize = SizeOf.estimate(object);
Change_Disk_Size += objByteSize;
boolean result = false;

if (Total_Disk_Size > Change_Disk_Size) {
writeFile(key,object,result);
}else {
if (Remove_Strategy.equalsIgnoreCase("FIFO")) {
String remove_key = putOrder.getFirst();
putOrder.remove(remove_key);
diskCache.remove(remove_key);
usedMap.remove(remove_key);
File remove_file = new File(Cache_Path +"//"+ remove_key + ".dat");
remove_file.delete();
Change_Disk_Size -= objByteSize;
writeFile(key,object,result);
result = true;
} else if (usedMap.size()>0 || Remove_Strategy.equalsIgnoreCase("LFU")) {
String remove_key = getLessKey();
putOrder.remove(remove_key);
diskCache.remove(remove_key);
usedMap.remove(remove_key);
File remove_file = new File(Cache_Path+"//"+ remove_key + ".dat");
remove_file.delete();
Change_Disk_Size -= objByteSize;
writeFile(key,object,result);
result = true;
}
}
return result;
}

private static void writeFile(String key , Object object,boolean result){
try {
WriteableObject wObject = (WriteableObject)object ;
File file = new File(Cache_Path +"//"+ key + ".dat");
OutputStream outputStream = new FileOutputStream(file);
DataOutputStream dos = new DataOutputStream(outputStream);
dos.writeUTF(wObject.getClass().getName());
wObject.write(outputStream);
dos.flush();
dos.close();
outputStream.flush();
outputStream.close();
diskCache.put(key, file);
putOrder.add(key);
result = true;
}catch (IOException e) {
e.printStackTrace();
result = false;
}
}


private static String getLessKey(){
String result_key = null;
int result_value = 0 ;
int index = 0 ;
for (Map.Entry<String, Integer> entry : usedMap.entrySet()) {
String temp_key = entry.getKey();
int temp_value = entry.getValue();
if (index==0) {
result_key = temp_key;
result_value = temp_value;
}else {
if (result_value > temp_value) {
result_key = temp_key;
result_value = temp_value;
}
}
index ++;
}
return result_key;
}

private String getProperty(String key, String defaultValue) {
if (props == null) {
synchronized (this) {
if (props == null) {
try {
InputStream stream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("/cache.properties");
if (stream == null) {
stream = DiskCache.class
.getResourceAsStream("/cache.properties");
}
props = new Properties();
props.load(stream);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return props.getProperty(key, defaultValue);
}
}


使用实现的接口类

public interface WriteableObject extends Serializable {
public void read(InputStream inputStream) throws IOException;

public boolean write(OutputStream outputStream) throws IOException;

}


使用实例

public class People implements WriteableObject {

private static final long serialVersionUID = 1L;

private String name;

private List<String> list;

public People(){
super();
}

public People(String name, List<String> list) {
this.name = name;
this.list = list;
}


@Override
public void read(InputStream inputStream) throws IOException {
DataInputStream dis = new DataInputStream(inputStream);
name = dis.readUTF();
int size = dis.readInt();
list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(dis.readLine());
}
}


@Override
public boolean write(OutputStream outputStream) throws IOException {
DataOutputStream dos = new DataOutputStream(outputStream);
dos.writeUTF(name);
dos.writeInt(list.size());
for (String obj : list) {
dos.writeBytes(obj);
}
dos.flush();
dos.close();
return true;
}


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}


public List<String> getList() {
return list;
}


public void setList(List<String> list) {
this.list = list;
}


}

这段代码就是使用的事例了:

DiskCache cache = DiskCache.getInstance();
for (int i = 0; i < 10; i++) {
String key = "myCache"+index;
cache.put(key, beanInstance());
}


其实这个在前面早就有所描述。不再复述了。。。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值