姿勢一
使用expiredAferWriter
優點
- 簡單
- 粗暴
缺點
- 同步阻塞問題:如果多個執行緒同時請求同一個過期的key,只有一個執行緒能夠獲得去載入快取的鎖,但是其他未獲取載入快取鎖的執行緒也會阻塞。
show me the code
姿勢二
使用expiredAfterWrite + refreshAfterWrite
使用注意
指定refreshAferWrite的時間小於expiredAfterWrite
必須使用LoadingCache
直接使用get獲取快取
優點
- 當到達重新整理時間之後,只會有一個執行緒獲得重新整理快取的鎖,其他執行緒直接返回快取中的舊值,僅阻塞重新整理快取的執行緒
缺點
- 重新整理快取的執行緒還是會被阻塞
show me the code
姿勢三
使用expiredAfterWrite + refreshAfterWrite + ListenableFuture
優點
- 重新整理快取的執行緒也不會被阻塞,而是直接返回
缺點
- 重新整理快取的執行緒得到的仍然是舊值
- 快取的重新整理或者重新載入還是得靠外部請求觸發,不能完全達到定時重新整理效果
注意
1. 不管上面那種方式,快取的載入和重新整理都需要外部呼叫(get)才觸發
2. 使用姿勢二和三要注意快取的重新整理過期時間要設定的比載入過期時間短,否則體現不出優勢
3. 如果當前請求快取時間距離最後一次時間已經超過過期時間,則會呼叫載入(load)方法而非重新整理(reload)方法來載入快取,此時會回退到姿勢一
4. 重新整理快取的同時也會重新整理快取下次過期的時間(在當前時間累加過期時間)
5. 具體邏輯參照**com.google.common.cache.LocalCache$Segment**。這裡貼出一些關鍵邏輯供各位參考:
只有在value!=null的時候(既未達到過期時間時)才會呼叫refresh方法
註冊了一個Listener來實現非同步重新整理