由於緩存大小爲3,依次查詢到c時,緩存已滿,當查詢d時,a將被移除,當查詢e時,b將被移除。
CacheBuilder的removalListener方法中,將其監聽器參數賦值給成員變量removalListener,在LocalCache構造函數中,又傳給LocalCache的刪除監聽器removalListener。至於removalNotificationQueue,也在LocalCache構造函數初始化:new ConcurrentLinkedQueue<RemovalNotification<K, V>>()。
RemovalNotification爲清除單條數據的通知,無論CacheBuilder中設置的鍵值引用級別是什麼,此類保存的是鍵值的強引用,若是鍵值已經被垃圾回收器收集,則可能爲空。
在引發緩存數據清除的操做中,都會將刪除消息放入隊列removalNotificationQueue中,入隊主體函數: void enqueueNotification(K key, int hash, ValueReference<K, V> valueReference, RemovalCause cause)
參數cause代表引起這次刪除操做的緣由,爲RemovalCause枚舉類型,緣由有如下幾種:
1)EXPLICIT:鍵值被用戶手動刪除,當用戶調用invalidate,invalidateAll,remove時, 會發生這種狀況 。
2)REPLACED:鍵值發生替換。當用戶調用put,refresh,putAll, replace時, 會發生這種狀況 。
3)COLLECTED:垃圾回收引發鍵值被自動清除,在使用weakKeys,weakValues 或 softValues時, 會發生這種狀況 。
4)EXPIRED:鍵值過時,在使用expireAfterAccess 或 expireAfterWrite時,會發生這種狀況。
5)SIZE:緩存大小限制引發鍵值被清除,在使用maximumSize 或 maximumWeight時,會發生這種狀況。
在入消息隊列時,使用的是Queue的offer方法,若是隊列已滿,將返回false,而不會報IllegalStateException異常。
對刪除消息的處理在下面函數中:
void processPendingNotifications() {
RemovalNotification<K, V> notification;
while ((notification = removalNotificationQueue.poll()) != null) {
try {
removalListener.onRemoval(notification);
} catch (Throwable e) {
logger.log(Level.WARNING, "Exception thrown by removal listener", e);
}
}
}
該函數被調用的過程以下:
processPendingNotifications
←runUnlockedCleanup
←cleanUp(清零readCount)
←postReadCleanup(readCount增1)
←postWriteCleanup
只要涉及鍵值的讀操做,都將執行postReadCleanup操做,每次執行postReadCleanup操做時readCount都增1,當其達到64時(DRAIN_THRESHOLD爲0x3F,即0011 1111),引起cleanUp操做。
if ((readCount.incrementAndGet() & DRAIN_THRESHOLD) == 0) {
而只要涉及鍵值的寫操做,都將執行postWriteCleanup操做。