姿勢一
使用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來實現異步刷新