1、guava缓存原理-get操作
org.spark_project.guava.cache.LocalCache#get(K, org.spark_project.guava.cache.CacheLoader<? super K,V>)
V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException {
int hash = this.hash(Preconditions.checkNotNull(key));
return this.segmentFor(hash).get(key, hash, loader); // @1
}
代码@1:从分段segment中获取key对应的value;
V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {
Object var16;
try {
if (this.count != 0) { // @1
LocalCache.ReferenceEntry<K, V> e = this.getEntry(key, hash);
if (e != null) { // @2
long now = this.map.ticker.read();
V value = this.getLiveValue(e, now);
if (value != null) {
this.recordRead(e, now);
this.statsCounter.recordHits(1);
Object var17 = this.scheduleRefresh(e, key, hash, value, now, loader);
return var17;
}
LocalCache.ValueReference<K, V> valueReference = e.getValueReference();
if (valueReference.isLoading()) {
Object var9 = this.waitForLoadingValue(e, key, valueReference);
return var9;
}
}
}
var16 = this.lockedGetOrLoad(key, hash, loader); // @3
} catch (ExecutionException var14) {
Throwable cause = var14.getCause();
if (cause instanceof Error) {
throw new ExecutionError((Error)cause);
}
if (cause instanceof RuntimeException) {
throw new UncheckedExecutionException(cause);
}
throw var14;
} finally {
this.postReadCleanup();
}
return var16;
}
代码@1: count是统计segment访问的变量,put时count+1,get时count-1;
代码@2: e!=null表明从需缓存中获取,通过e.getValueReference()获取引用,guava中的引用有下面几种,基于jdk的强/软/弱引用来实现
!
代码@3: 从用户定义的load方法加载数据;
V getLiveValue(LocalCache.ReferenceEntry<K, V> entry, long now) {
if (entry.getKey() == null) { ///如果为空,返回空
this.tryDrainReferenceQueues();
return null;
} else {
V value = entry.getValueReference().get();
if (value == null) {
this.tryDrainReferenceQueues();
return null;
} else if (this.map.isExpired(entry, now)) { // @1
this.tryExpireEntries(now);
return null;
} else {
return value;
}
}
}
代码@1:判断entry是否过期,这里是直接在get操作时判断是否过期,并expire将entry移除;并没有使用后台线程轮询,而是采用这种惰性删除的策略,如果一直不访问,可能存在内存泄漏问题。
V lockedGetOrLoad(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {
LocalCache.ValueReference<K, V> valueReference = null;
LocalCache.LoadingValueReference<K, V> loadingValueReference = null;
boolean createNewEntry = true;
this.lock();// @1
LocalCache.ReferenceEntry e;
try {
long now = this.map.ticker.read();
this.preWriteCleanup(now);
int newCount = this.count - 1;// @2
AtomicReferenceArray<LocalCache.ReferenceEntry<K, V>> table = this.table;
int index = hash & table.length() - 1;
LocalCache.ReferenceEntry<K, V> first = (LocalCache.ReferenceEntry)table.get(index);
for(e = first; e != null; e = e.getNext()) {
K entryKey = e.getKey();
if (e.getHash() == hash && entryKey != null && this.map.keyEquivalence.equivalent(key, entryKey)) {
valueReference = e.getValueReference();
if (valueReference.isLoading()) {
createNewEntry = false;
} else {
V value = valueReference.get();
if (value == null) {
this.enqueueNotification(entryKey, hash, valueReference, RemovalCause.COLLECTED);
} else {
if (!this.map.isExpired(e, now)) {
this.recordLockedRead(e, now);
this.statsCounter.recordHits(1);
Object var16 = value;
return var16;
}
this.enqueueNotification(entryKey, hash, valueReference, RemovalCause.EXPIRED);
}
this.writeQueue.remove(e);
this.accessQueue.remove(e);
this.count = newCount;
}
break;
}
}
if (createNewEntry) {// @3
loadingValueReference = new LocalCache.LoadingValueReference();
if (e == null) {
e = this.newEntry(key, hash, first);
e.setValueReference(loadingValueReference);
table.set(index, e);
} else {
e.setValueReference(loadingValueReference);
}
}
} finally {
this.unlock();
this.postWriteCleanup();
}
if (createNewEntry) { // @4
Object var19;
try {
synchronized(e) {
var19 = this.loadSync(key, hash, loadingValueReference, loader);
}
} finally {
this.statsCounter.recordMisses(1);
}
return var19;
} else {
return this.waitForLoadingValue(e, key, valueReference);
}
}
代码@1 segment是一个继承了ReentrantLock的锁,这里进行加锁来解决缓存穿透
代码@2 对count-1,上面提过count是统计key的活跃度
代码@3 创建一个新的引用,entry持有一个它
代码@4:同步调用load方法获取用户提供的value,并将value赋值给loadingValueReference
V loadSync(K key, int hash, LocalCache.LoadingValueReference<K, V> loadingValueReference, CacheLoader<? super K, V> loader) throws ExecutionException {
ListenableFuture<V> loadingFuture = loadingValueReference.loadFuture(key, loader); //@1
return this.getAndRecordStats(key, hash, loadingValueReference, loadingFuture);
}
代码@1: 加载用户设置的value,并赋值到loadingValueReference
public ListenableFuture<V> loadFuture(K key, CacheLoader<? super K, V> loader) {
this.stopwatch.start();
Object previousValue = this.oldValue.get();
try {
if (previousValue == null) {
V newValue = loader.load(key); // @1
return (ListenableFuture)(this.set(newValue) ? this.futureValue : Futures.immediateFuture(newValue)); // @2
} else {
ListenableFuture<V> newValue = loader.reload(key, previousValue);
return newValue != null ? newValue : Futures.immediateFuture((Object)null);
}
} catch (Throwable var5) {
}
}
代码@1 加载用户的value
代码@2 赋值给并赋值到loadingValueReference