内存缓存
接口MemoryCache。默认实现LruResourceCache。
public class LruResourceCache <Key, Resource> {
// 缓存的容器。Linkedxxx.accessOrder置为true,天生带Lru性质。
private final LinkedHashMap<Key, Resource> cache = new LinkedHashMap<>(100, 0.75f, true);
private int maxSize;
private final int initialMaxSize;
private int currentSize = 0;
// 读取
public Resource get(Key key) {
return cache.get(key);
}
// 储存
public Resource put(Key key, Resource item) {
final int itemSize = item.getSize();
// 如果储存对象大于最大容量,直接回收不储存
if (itemSize >= maxSize) {
onItemEvicted(key, item);
return null;
}
// 储存,然后Lru清理空间
final Resource result = cache.put(key, item);
currentSize += getSize(item);
trimToSize(maxSize);
return result;
}
// 清理空间到size
protected void trimToSize(int size) {
Map.Entry<T, Y> last;
while (currentSize > size) {
last = cache.entrySet().iterator().next();
final Resource toRemove = last.getValue();
currentSize -= getSize(toRemove);
final T key = last.getKey();
cache.remove(key);
}
}
}
磁盘缓存
接口DiskCache。默认实现DiskLruCacheWrapper。
// 封装ReentrantLock和被重入次数
class WriteLock {
final Lock lock = new ReentrantLock();
int interestedThreads;
}
// 多线程环境下的缓存,注意加锁的位置
class WriteLockPool {
private static final int MAX_POOL_SIZE = 10;
private final Queue<WriteLock> pool = new ArrayDeque<WriteLock>();
WriteLock obtain() {
WriteLock result;
synchronized (pool) {
result = pool.poll();
}
if (result == null) {
result = new WriteLock();
}
return result;
}
void offer(WriteLock writeLock) {
synchronized (pool) {
if (pool.size() < MAX_POOL_SIZE) {
pool.offer(writeLock);
}
}
}
}
class DiskLruCache // 缓存操作的真正实现类。缓存容器也是LinkedHashMap。
class DiskCacheWriteLocker {
private final Map<Key, WriteLock> locks = new HashMap<Key, WriteLock>();
private final WriteLockPool writeLockPool = new WriteLockPool();
// 申请锁
void acquire(Key key) {
WriteLock writeLock;
synchronized (this) {
writeLock = locks.get(key);
if (writeLock == null) {
writeLock = writeLockPool.obtain();
locks.put(key, writeLock);
}
writeLock.interestedThreads++;
}
// 注意lock()是在synchronized{}外面的
writeLock.lock.lock();
}
// 释放锁
void release(Key key) {
WriteLock writeLock;
synchronized (this) {
writeLock = locks.get(key);
if (writeLock == null || writeLock.interestedThreads <= 0) {
throw new IllegalArgumentException();
}
// 如果没有线程占用它,可以回收
if (--writeLock.interestedThreads == 0) {
WriteLock removed = locks.remove(key);
if (!removed.equals(writeLock)) {
throw new IllegalStateException();
}
writeLockPool.offer(removed);
}
}
// 注意unlock()是在synchronized{}外面的
writeLock.lock.unlock();
}
}
class DiskLruCacheWrapper implements DiskCache {
private static final int APP_VERSION = 1;
private static final int VALUE_COUNT = 1;
// 单例
private static DiskLruCacheWrapper wrapper = null;
private final DiskCacheWriteLocker writeLocker = new DiskCacheWriteLocker();
private final SafeKeyGenerator safeKeyGenerator;
private final File directory; // 缓存目录
private final int maxSize;
private DiskLruCache diskLruCache;
public static synchronized DiskCache get(File directory, int maxSize) {
if (wrapper == null) {
wrapper = new DiskLruCacheWrapper(directory, maxSize);
}
return wrapper;
}
protected DiskLruCacheWrapper(File directory, int maxSize) {
this.directory = directory;
this.maxSize = maxSize;
this.safeKeyGenerator = new SafeKeyGenerator();
}
private synchronized DiskLruCache getDiskCache() throws IOException {
if (diskLruCache == null) {
diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
}
return diskLruCache;
}
private synchronized void resetDiskCache() {
diskLruCache = null;
}
// 读取。
@Override
public File get(Key key) {
String safeKey = safeKeyGenerator.getSafeKey(key);
File result = null;
try {
final DiskLruCache.Value value = getDiskCache().get(safeKey);
if (value != null) {
result = value.getFile(0);
}
} catch (IOException e) {
}
return result;
}
// 储存。
@Override
public void put(Key key, Writer writer) {
String safeKey = safeKeyGenerator.getSafeKey(key);
writeLocker.acquire(key);
try {
DiskLruCache.Editor editor = getDiskCache().edit(safeKey);
if (editor != null) {
try {
File file = editor.getFile(0);
if (writer.write(file)) {
editor.commit();
}
} finally {
editor.abortUnlessCommitted();
}
}
} catch (IOException e) {
} finally {
writeLocker.release(key);
}
}
}