简单描述:
Glide缓存读取的顺序是:Lru算法缓存、弱引用缓存、磁盘缓存
Glide缓存写入的顺序是:弱引用缓存、Lru算法缓存、磁盘缓存(不准确)

下面叙述一下三级缓存的流程:
当我们的APP中想要加载某张图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,如果LruCache中没有,则去WeakReference中寻找,如果WeakReference中有,则从WeakReference中取出图片使用,同时将图片重新放回到LruCache中,如果WeakReference中也没有图片,则去文件系统中寻找,如果有则取出来使用,同时将图片添加到LruCache中,如果没有,则连接网络从网上下载图片。图片下载完成后,将图片保存到文件系统中,然后放到LruCache中。

严格来讲,并没有什么Glide的三级缓存,因为Glide的缓存只有两个模块,一个是内存缓存,一个是磁盘缓存。其中内存缓存又分为Lru算法的缓存和弱引用缓存。

LruCache算法,Least Recently Used,又称为近期最少使用算法。主要算法原理就是把最近所使用的对象的强引用存储在LinkedHashMap上,并且,把最近最少使用的对象在缓存池达到预设值之前从内存中移除。

public class LruCache<T, Y> {
    private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
}

弱引用缓存:

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
    //弱引用缓存
    private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
    ...
    activeResources = new HashMap<Key, WeakReference<EngineResource<?>>>();
}

我们先来看缓存读取:Lru算法缓存、弱引用缓存、磁盘缓存
首先 memoryCache的初始值是一个LruResourceCache对象,即默认是lru算法的缓存

GlideBuilder.java
	private MemoryCache memoryCache;
    Glide  createGlide() {
		memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
    }
 
Engine.java
	private final MemoryCache cache;
	public <T, Z, R> LoadStatus load(...){
		...
		//获取Lru算法的缓存,如果没有,就从弱引用中获取缓存
		EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
		...
		//从弱引用中获取缓存
		EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
		...
		//从磁盘中获取缓存
		EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, 
               fetcher, loadProvider, transformation,transcoder,             
               diskCacheProvider, diskCacheStrategy, priority);
	}

接下来我们看缓存写入:弱引用缓存、Lru算法缓存、磁盘缓存
内存缓存的写入:
EngineResource是用一个acquired(int)变量用来记录图片被引用的次数,调用acquire()方法会让变量加1,
调用release()方法会让变量减1。
acquired变量大于0的时候,说明图片正在使用中,也就应该放到activeResources弱引用缓存当中;
如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会调用方法来释放资源,
这里首先会将缓存图片从activeResources中移除,然后再将它put到LruResourceCache当中。
这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
    ...    
 
    @Override
    public void onEngineJobComplete(Key key, EngineResource<?> resource) {
        Util.assertMainThread();
        // A null resource indicates that the load failed, usually due to an exception.
        if (resource != null) {
            resource.setResourceListener(key, this);
            if (resource.isCacheable()) {
                activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
            }
        }
        jobs.remove(key);
    }
 
    ...
}

现在就非常明显了,可以看到,在第13行,回调过来的EngineResource被put到了activeResources当中,也就是在这里写入的缓存。

那么这只是弱引用缓存,还有另外一种LruCache缓存是在哪里写入的呢?这就要介绍一下EngineResource中的一个引用机制了。观察刚才的handleResultOnMainThread()方法,在第15行和第19行有调用EngineResource的acquire()方法,在第23行有调用它的release()方法。其实,EngineResource是用一个acquired变量用来记录图片被引用的次数,调用acquire()方法会让变量加1,调用release()方法会让变量减1,代码如下所示:

class EngineResource<Z> implements Resource<Z> {
 
    private int acquired;
    ...
 
    void acquire() {
        if (isRecycled) {
            throw new IllegalStateException("Cannot acquire a recycled resource");
        }
        if (!Looper.getMainLooper().equals(Looper.myLooper())) {
            throw new IllegalThreadStateException("Must call acquire on the main thread");
        }
        ++acquired;
    }
 
    void release() {
        if (acquired <= 0) {
            throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
        }
        if (!Looper.getMainLooper().equals(Looper.myLooper())) {
            throw new IllegalThreadStateException("Must call release on the main thread");
        }
        if (--acquired == 0) {
            listener.onResourceReleased(key, this);
        }
    }
}

也就是说,当acquired变量大于0的时候,说明图片正在使用中,也就应该放到activeResources弱引用缓存当中。而经过release()之后,如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会在第24行调用listener的onResourceReleased()方法来释放资源,这个listener就是Engine对象,我们来看下它的onResourceReleased()方法:

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
 
    private final MemoryCache cache;
    private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
    ...    
 
    @Override
    public void onResourceReleased(Key cacheKey, EngineResource resource) {
        Util.assertMainThread();
        activeResources.remove(cacheKey);
        if (resource.isCacheable()) {
            cache.put(cacheKey, resource);
        } else {
            resourceRecycler.recycle(resource);
        }
    }
 
    ...
}

可以看到,这里首先会将缓存图片从activeResources中移除,然后再将它put到LruResourceCache当中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。
这就是Glide内存缓存的实现原理。