一.LruCache类
Glide的内存缓存内部使用的是LruCache类
LruCache类源码
public class LruCache<T, Y> {
private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
private int maxSize;
private final int initialMaxSize;
private int currentSize = 0;
/**
* Constructor for LruCache.
*
* @param size The maximum size of the cache, the units must match the units used in {@link #getSize(Object)}.
*/
public LruCache(int size) {
this.initialMaxSize = size;
this.maxSize = size;
}
/**
* Sets a size multiplier that will be applied to the size provided in the constructor to set the new size of the
* cache. If the new size is less than the current size, entries will be evicted until the current size is less
* than or equal to the new size.
*
* @param multiplier The multiplier to apply.
*/
public void setSizeMultiplier(float multiplier) {
if (multiplier < 0) {
throw new IllegalArgumentException("Multiplier must be >= 0");
}
maxSize = Math.round(initialMaxSize * multiplier);
evict();
}
/**
* Returns the size of a given item, defaulting to one. The units must match those used in the size passed in to the
* constructor. Subclasses can override this method to return sizes in various units, usually bytes.
*
* @param item The item to get the size of.
*/
protected int getSize(Y item) {
return 1;
}
/**
* A callback called whenever an item is evicted from the cache. Subclasses can override.
*
* @param key The key of the evicted item.
* @param item The evicted item.
*/
protected void onItemEvicted(T key, Y item) {
// optional override
}
/**
* Returns the current maximum size of the cache in bytes.
*/
public int getMaxSize() {
return maxSize;
}
/**
* Returns the sum of the sizes of all items in the cache.
*/
public int getCurrentSize() {
return currentSize;
}
/**
* Returns true if there is a value for the given key in the cache.
*
* @param key The key to check.
*/
public boolean contains(T key) {
return cache.containsKey(key);
}
/**
* Returns the item in the cache for the given key or null if no such item exists.
*
* @param key The key to check.
*/
public Y get(T key) {
return cache.get(key);
}
/**
* Adds the given item to the cache with the given key and returns any previous entry for the given key that may
* have already been in the cache.
*
* <p>
* If the size of the item is larger than the total cache size, the item will not be added to the cache and
* instead {@link #onItemEvicted(Object, Object)} will be called synchronously with the given key and item.
* </p>
*
* @param key The key to add the item at.
* @param item The item to add.
*/
public Y put(T key, Y item) {
final int itemSize = getSize(item);
if (itemSize >= maxSize) {
onItemEvicted(key, item);
return null;
}
final Y result = cache.put(key, item);
if (item != null) {
currentSize += getSize(item);
}
if (result != null) {
// TODO: should we call onItemEvicted here?
currentSize -= getSize(result);
}
evict();
return result;
}
/**
* Removes the item at the given key and returns the removed item if present, and null otherwise.
*
* @param key The key to remove the item at.
*/
public Y remove(T key) {
final Y value = cache.remove(key);
if (value != null) {
currentSize -= getSize(value);
}
return value;
}
/**
* Clears all items in the cache.
*/
public void clearMemory() {
trimToSize(0);
}
/**
* Removes the least recently used items from the cache until the current size is less than the given size.
*
* @param size The size the cache should be less than.
*/
protected void trimToSize(int size) {
Map.Entry<T, Y> last;
while (currentSize > size) {
last = cache.entrySet().iterator().next();
final Y toRemove = last.getValue();
currentSize -= getSize(toRemove);
final T key = last.getKey();
cache.remove(key);
onItemEvicted(key, toRemove);
}
}
private void evict() {
trimToSize(maxSize);
}
}
源码分析
源码可知,LruCache类中使用了LinkedHashMap实现内存缓存。
LinkedHashMap有一个三个参数的构造方法
public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
参数1 initialCapacity:初始化LinkedHashMap的大小。
参数2 loadFactor:负载因子。
参数3 accessOrder:按照什么顺序向LinkedHashMap中插入数据。true:按照最近访问量的高低排序,false:按照插入顺序排序。
LruCache类中使用LinkedHashMap时传参如下
private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
也就是说LruCache类中使用LinkedHashMap时
<1> 初始化值大小:100。
<2> 加载因子:0.75f。
<3> 向LinkedHashMap中插入数据:按照最近访问量的高低排序。
二.DiskLruCache
Glide的磁盘缓存内部使用的是DiskLruCache类
DiskLruCache类部分源码
public final class DiskLruCache implements Closeable {
private final LinkedHashMap<String, Entry> lruEntries =new LinkedHashMap<String, Entry>(0, 0.75f, true);
final ThreadPoolExecutor executorService =
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
private final Callable<Void> cleanupCallable = new Callable<Void>() {
public Void call() throws Exception {
synchronized (DiskLruCache.this) {
if (journalWriter == null) {
return null; // Closed.
}
trimToSize();
if (journalRebuildRequired()) {
rebuildJournal();
redundantOpCount = 0;
}
}
return null;
}
};
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
this.directory = directory;
this.appVersion = appVersion;
this.journalFile = new File(directory, JOURNAL_FILE);
this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
this.valueCount = valueCount;
this.maxSize = maxSize;
}
/**
* Opens the cache in {@code directory}, creating a cache if none exists
* there.
*
* @param directory a writable directory
* @param valueCount the number of values per cache entry. Must be positive.
* @param maxSize the maximum number of bytes this cache should use to store
* @throws IOException if reading or writing the cache directory fails
*/
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
throws IOException {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
if (valueCount <= 0) {
throw new IllegalArgumentException("valueCount <= 0");
}
// If a bkp file exists, use it instead.
File backupFile = new File(directory, JOURNAL_FILE_BACKUP);
if (backupFile.exists()) {
File journalFile = new File(directory, JOURNAL_FILE);
// If journal file also exists just delete backup file.
if (journalFile.exists()) {
backupFile.delete();
} else {
renameTo(backupFile, journalFile, false);
}
}
// Prefer to pick up where we left off.
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
if (cache.journalFile.exists()) {
try {
cache.readJournal();
cache.processJournal();
return cache;
} catch (IOException journalIsCorrupt) {
System.out
.println("DiskLruCache "
+ directory
+ " is corrupt: "
+ journalIsCorrupt.getMessage()
+ ", removing");
cache.delete();
}
}
// Create a new empty cache.
directory.mkdirs();
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
cache.rebuildJournal();
return cache;
}
}
源码分析
源码可知,DiskLruCache类中也使用了LinkedHashMap实现磁盘缓存。
1.DiskLruCache类中使用LinkedHashMap时传参如下
private final LinkedHashMap<String, Entry> lruEntries =new LinkedHashMap<String, Entry>(0, 0.75f, true);
也就是说DiskLruCache类中使用LinkedHashMap时
<1> 初始化值大小:0。
<2> 加载因子:0.75f。
<3> 向LinkedHashMap中插入数据:按照最近访问量的高低排序。
2.Glide的磁盘缓存还用到了ThreadPoolExecutor(线程池核心类)
final ThreadPoolExecutor executorService =new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
参数 corePoolSize(核心线程的大小):0
参数 maximumPoolSize(线程池中允许的最大线程数):1
参数 keepAliveTime(线程保持存活的时间):60
参数 TimeUnit(参数keepAliveTime的时间单位):秒
参数 workQueue(线程池中的任务队列): LinkedBlockingQueue:这个队列接收到任务的时候,如果当前已经创建的核心线程数小于线程池的核心线程数上限,则新建线程(核心线程)处理任务;如果当前已经创建的核心线程数等于核心线程数上限,则进入队列等待
参数 threadFactory(线程工厂):默认
参数 RejectedExecutionHandler(表示当拒绝处理任务时的策略):默认 这是当任务队列和线程池都满了时所采取的应对策略,默认是AbordPolicy, 表示无法处理新任务,并抛出 RejectedExecutionException 异常
使用submit方式提交(submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果)
executorService.submit(cleanupCallable);
附:线程池详解
https://blog.csdn.net/weixin_37730482/article/details/72781767