google guava缓存穿透使用ReentrantLock(可重入锁)实现,当某个key在缓存中失效并执行回源,其他线程将会阻塞,直到回源完成。
1)ReentrantLock管理
LocalCache中包含内部类Segment,该类继承了ReentrantLock
static class Segment<K, V> extends ReentrantLock {
在LocalCache构造函数中,会初始化Segment<K, V>数组,默认大小为4,可以通过builder的concurrencyLevel来控制大小。数组大小增长为2的倍数,如果设置了concurrencyLevel=100,则实际的大小为64.
2)回源管理
当我们请求一个key的数据并需要回源的时候,LocalCache会根据key来进行hash,并指定某个Segment<K, V>,执行get方法
V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException {
int hash = hash(checkNotNull(key));
return segmentFor(hash).get(key, hash, loader);
}
如果key需要回源,执行Segment<K, V>::lockedGetOrLoad方法,注意到lock()。lock会阻塞其他线程,直到回源结束