提交 31640f60 编写于 作者: S Sam Judd

Ensure data is available when disk cache put completes.

Fixes #429.
上级 31fc07fd
package com.bumptech.glide.load.engine.cache;
import com.bumptech.glide.load.Key;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Keeps a map of keys to locks that allows locks to be removed from the map when no longer in use
* so the size of the collection is bounded.
*
* <p> This class will be accessed by multiple threads in a thread pool and ensures that the
* number of threads interested in each lock is updated atomically so that when the count reaches
* 0, the lock can safely be removed from the map. </p>
*/
final 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++;
}
writeLock.lock.lock();
}
void release(Key key) {
WriteLock writeLock;
synchronized (this) {
writeLock = locks.get(key);
if (writeLock == null || writeLock.interestedThreads <= 0) {
throw new IllegalArgumentException(
"Cannot release a lock that is not held" + ", key: " + key + ", interestedThreads: "
+ (writeLock == null ? 0 : writeLock.interestedThreads));
}
if (--writeLock.interestedThreads == 0) {
WriteLock removed = locks.remove(key);
if (!removed.equals(writeLock)) {
throw new IllegalStateException("Removed the wrong lock"
+ ", expected to remove: " + writeLock
+ ", but actually removed: " + removed
+ ", key: " + key);
}
writeLockPool.offer(removed);
}
}
writeLock.lock.unlock();
}
private static class WriteLock {
final Lock lock = new ReentrantLock();
int interestedThreads;
}
private static 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);
}
}
}
}
}
......@@ -25,6 +25,7 @@ public class DiskLruCacheWrapper implements DiskCache {
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;
......@@ -87,6 +88,7 @@ public class DiskLruCacheWrapper implements DiskCache {
@Override
public void put(Key key, Writer writer) {
String safeKey = safeKeyGenerator.getSafeKey(key);
writeLocker.acquire(key);
try {
DiskLruCache.Editor editor = getDiskCache().edit(safeKey);
// Editor will be null if there are two concurrent puts. In the worst case we will just silently fail.
......@@ -104,6 +106,8 @@ public class DiskLruCacheWrapper implements DiskCache {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to put to disk cache", e);
}
} finally {
writeLocker.release(key);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册