2021SC@SDUSC
总览图
代码
public interface CacheStorage { public Object get(Object key); public void put(Object key, Object value); public void remove(Object key); public void clear(); }
作用:Cache storage抽象了高速缓存的存储方面——将对象(object)与键(key)相关联,通过键进行检索和删除。它实际上是java.util.Map的一个子接口。
代码
public interface CacheStorageWithGetSize extends CacheStorage { int getSize(); }
作用:具有getSize()方法的缓存存储,用于返回当前缓存条目的数量。
代码
public interface ConcurrentCacheStorage extends CacheStorage { public boolean isConcurrent(); }
作用:一个可选的缓存存储接口,它知道是否可以在不同步的情况下并发访问。
代码
public class NullCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize { public static final NullCacheStorage INSTANCE = new NullCacheStorage(); @Override public boolean isConcurrent() { return true; } @Override public Object get(Object key) { return null; } @Override public void put(Object key, Object value) { // do nothing } @Override public void remove(Object key) { // do nothing } @Override public void clear() { // do nothing } public int getSize() { return 0; } }
作用:一个不存储任何东西的高速缓存存储器。如果不需要缓存,可以使用这个。
代码
public class SoftCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize { private static final Method atomicRemove = getAtomicRemoveMethod(); private final ReferenceQueue queue = new ReferenceQueue(); private final Map map; private final boolean concurrent; public SoftCacheStorage() { this(new ConcurrentHashMap()); } @Override public boolean isConcurrent() { return concurrent; } public SoftCacheStorage(Map backingMap) { map = backingMap; this.concurrent = map instanceof ConcurrentMap; } @Override public Object get(Object key) { processQueue(); Reference ref = (Reference) map.get(key); return ref == null ? null : ref.get(); } @Override public void put(Object key, Object value) { processQueue(); map.put(key, new SoftValueReference(key, value, queue)); } @Override public void remove(Object key) { processQueue(); map.remove(key); } @Override public void clear() { map.clear(); processQueue(); } @Override public int getSize() { processQueue(); return map.size(); } private void processQueue() { for (; ; ) { SoftValueReference ref = (SoftValueReference) queue.poll(); if (ref == null) { return; } Object key = ref.getKey(); if (concurrent) { try { atomicRemove.invoke(map, new Object[] { key, ref }); } catch (IllegalAccessException | InvocationTargetException e) { throw new UndeclaredThrowableException(e); } } else if (map.get(key) == ref) { map.remove(key); } } } private static final class SoftValueReference extends SoftReference { private final Object key; SoftValueReference(Object key, Object value, ReferenceQueue queue) { super(value, queue); this.key = key; } Object getKey() { return key; } } private static Method getAtomicRemoveMethod() { try { return Class.forName("java.util.concurrent.ConcurrentMap").getMethod("remove", new Class[] { Object.class, Object.class }); } catch (ClassNotFoundException e) { return null; } catch (NoSuchMethodException e) { throw new UndeclaredThrowableException(e); } } }
作用:软缓存存储是一种使用SoftReference对象来保存传递给它的对象的缓存存储,因此允许垃圾收集器在确定想要释放内存时清除缓存。这个类的线程安全程度与其底层映射相同。无参数构造函数使用自2.3.24或Java 5以上的线程安全映射。
代码
public class StrongCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize { private final Map map = new ConcurrentHashMap(); @Override public boolean isConcurrent() { return true; } @Override public Object get(Object key) { return map.get(key); } @Override public void put(Object key, Object value) { map.put(key, value); } @Override public void remove(Object key) { map.remove(key); } @Override public int getSize() { return map.size(); } @Override public void clear() { map.clear(); } }
作用:强缓存存储是简单封装Map的缓存存储。它持有对传递给它的所有对象的强引用,因此可以防止在垃圾收集期间清除缓存。
代码
public class MruCacheStorage implements CacheStorageWithGetSize { private final MruEntry strongHead = new MruEntry(); private final MruEntry softHead = new MruEntry(); { softHead.linkAfter(strongHead); } private final Map map = new HashMap(); private final ReferenceQueue refQueue = new ReferenceQueue(); private final int strongSizeLimit; private final int softSizeLimit; private int strongSize = 0; private int softSize = 0; public MruCacheStorage(int strongSizeLimit, int softSizeLimit) { if (strongSizeLimit < 0) throw new IllegalArgumentException("strongSizeLimit < 0"); if (softSizeLimit < 0) throw new IllegalArgumentException("softSizeLimit < 0"); this.strongSizeLimit = strongSizeLimit; this.softSizeLimit = softSizeLimit; } @Override public Object get(Object key) { removeClearedReferences(); MruEntry entry = (MruEntry) map.get(key); if (entry == null) { return null; } relinkEntryAfterStrongHead(entry, null); Object value = entry.getValue(); if (value instanceof MruReference) { // This can only happen with strongSizeLimit == 0 return ((MruReference) value).get(); } return value; } @Override public void put(Object key, Object value) { removeClearedReferences(); MruEntry entry = (MruEntry) map.get(key); if (entry == null) { entry = new MruEntry(key, value); map.put(key, entry); linkAfterStrongHead(entry); } else { relinkEntryAfterStrongHead(entry, value); } } @Override public void remove(Object key) { removeClearedReferences(); removeInternal(key); } private void removeInternal(Object key) { MruEntry entry = (MruEntry) map.remove(key); if (entry != null) { unlinkEntryAndInspectIfSoft(entry); } } @Override public void clear() { strongHead.makeHead(); softHead.linkAfter(strongHead); map.clear(); strongSize = softSize = 0; // Quick refQueue processing while (refQueue.poll() != null); } private void relinkEntryAfterStrongHead(MruEntry entry, Object newValue) { if (unlinkEntryAndInspectIfSoft(entry) && newValue == null) { // Turn soft reference into strong reference, unless is was cleared MruReference mref = (MruReference) entry.getValue(); Object strongValue = mref.get(); if (strongValue != null) { entry.setValue(strongValue); linkAfterStrongHead(entry); } else { map.remove(mref.getKey()); } } else { if (newValue != null) { entry.setValue(newValue); } linkAfterStrongHead(entry); } } private void linkAfterStrongHead(MruEntry entry) { entry.linkAfter(strongHead); if (strongSize == strongSizeLimit) { // softHead.previous is LRU strong entry MruEntry lruStrong = softHead.getPrevious(); // Attila: This is equaivalent to strongSizeLimit != 0 // DD: But entry.linkAfter(strongHead) was just executed above, so // lruStrong != strongHead is true even if strongSizeLimit == 0. if (lruStrong != strongHead) { lruStrong.unlink(); if (softSizeLimit > 0) { lruStrong.linkAfter(softHead); lruStrong.setValue(new MruReference(lruStrong, refQueue)); if (softSize == softSizeLimit) { // List is circular, so strongHead.previous is LRU soft entry MruEntry lruSoft = strongHead.getPrevious(); lruSoft.unlink(); map.remove(lruSoft.getKey()); } else { ++softSize; } } else { map.remove(lruStrong.getKey()); } } } else { ++strongSize; } } private boolean unlinkEntryAndInspectIfSoft(MruEntry entry) { entry.unlink(); if (entry.getValue() instanceof MruReference) { --softSize; return true; } else { --strongSize; return false; } } private void removeClearedReferences() { for (; ; ) { MruReference ref = (MruReference) refQueue.poll(); if (ref == null) { break; } removeInternal(ref.getKey()); } } public int getStrongSizeLimit() { return strongSizeLimit; } public int getSoftSizeLimit() { return softSizeLimit; } public int getStrongSize() { return strongSize; } public int getSoftSize() { removeClearedReferences(); return softSize; } @Override public int getSize() { return getSoftSize() + getStrongSize(); } private static final class MruEntry { private MruEntry prev; private MruEntry next; private final Object key; private Object value; MruEntry() { makeHead(); key = value = null; } MruEntry(Object key, Object value) { this.key = key; this.value = value; } Object getKey() { return key; } Object getValue() { return value; } void setValue(Object value) { this.value = value; } MruEntry getPrevious() { return prev; } void linkAfter(MruEntry entry) { next = entry.next; entry.next = this; prev = entry; next.prev = this; } void unlink() { next.prev = prev; prev.next = next; prev = null; next = null; } void makeHead() { prev = next = this; } } private static class MruReference extends SoftReference { private final Object key; MruReference(MruEntry entry, ReferenceQueue queue) { super(entry.getValue(), queue); this.key = entry.getKey(); } Object getKey() { return key; } } }
作用:实现两级最近使用缓存的缓存存储。在第一层中,项被强引用到指定的最大值。当超过最大值时,最近最少使用的项被移动到第二级缓存,在那里它们被软引用,直到另一个第二级缓存,在那里它们被软引用,直到另一个最近使用的项被完全丢弃。这个缓存存储是StrongCacheStorage和SoftCacheStorage的一般化-两者的效果都可以通过设置一个最大值为零,另一个最大值为最大的正整数来实现。
注:Freemarker代码来自FreeMarker 中文官方参考手册
新手写的代码分析,文章若有错误还请指出