本地缓存之Guava简单使用
文章目錄
- 使用場景
- Guava Cache 的優勢
- Guava Cache使用
- CacheLoader
- Callable
- 刪除
- 主動刪除
- 過期刪除
- 基于容量刪除
- 引用刪除
- 高級用法
- 并發設置
- 更新鎖定
- GuavaCache高級實戰之疑難問題
- GuavaCache會oom(內存溢出)嗎
- GuavaCache緩存到期就會立即清除嗎
- GuavaCache如何找出最久未使用的數據
使用場景
隨著互聯網用戶越來越多,并發量、吞吐量越來越大
本地緩存的應用場景:
例如:拉勾網首頁,由于首頁經常被訪問,可以將職位信息:java開發、大數據開發等放在本地緩存中。
guava cache:高并發,不需要持久化
currentHashMap:高并發
Ehcached:持久化 二級緩存
Guava Cache 的優勢
緩存機制淘汰算法可參考博文:本地緩存之LRU FIFO實現
存
Guava Cache使用
Cache創建:
| maximumSize | 容量 |
| expireAfterWrite | 緩存項在給定時間內沒有被寫訪問(創建或覆蓋),則回收 |
| recordStats | 緩存項在給定時間內沒有被讀/寫訪問,則回收 |
| removalListener | 移除監聽器 |
| weakKeys | 弱引用存儲鍵,當鍵沒有其它(強或軟)引用時,緩存項可以被垃圾回收 |
| weakValues | 使用弱引用存儲值。當值沒有其它(強或軟)引用時,緩存項可以被垃圾回收 |
| concurrencyLevel | 并發操作 |
CacheLoader、Callable功能相同,都是在調用get方法時候,如果緩存不存在則指定數據源加載
CacheLoader
在創建緩存對象初始化時使用
模擬數據源
public static HashMap<Integer, Integer> sourceMap = new HashMap<>();static {for (int i = 0; i < 10; i++){sourceMap.put(i, i);}}使用demo
public static void main(String[] args) throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});for (int i = 0; i < 10; i++){cache.get(i);}System.out.println(cache.size());System.out.println(cache.asMap());}Callable
調用get方法時當緩存數據不存在時候從數據源加載數據
使用demo:
@Testpublic void call() throws ExecutionException {Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).build();Object value = cache.get(1, new Callable<Integer>() {@Overridepublic Integer call() throws Exception {return sourceMap.get(1);}});System.out.println(value);}刪除
主動刪除
@Testpublic void doDel() throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).expireAfterAccess(3, TimeUnit.SECONDS).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});initCache(cache);//主動刪除 key為1cache.invalidate(1);System.out.println("主動刪除");displayCache(cache);// 批量刪除cache.invalidateAll(Arrays.asList(1,2));System.out.println("批量刪除");displayCache(cache);}過期刪除
expireAfterAccess:如果在一定時間內沒被訪問則數據過期
@Testpublic void expireTimeDel() throws ExecutionException, InterruptedException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).expireAfterAccess(3, TimeUnit.SECONDS).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});initCache(cache);Thread.sleep(1000);cache.getIfPresent(1);Thread.sleep(2000);displayCache(cache);}基于容量刪除
@Testpublic void sizeDel() throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(1).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});Object v = cache.get(1);System.out.println(v);//自動刪除1Object v2 = cache.get(2);displayCache(cache);}引用刪除
開啟weakValues功能,采用弱引用,對引用不了解的可以看看,我的文章
@Testpublic void referenceDel(){Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(3).weakValues().build();cache.put("1",new Object());//強制垃圾回收System.gc();System.out.println(cache.getIfPresent("1"));}高級用法
并發設置
設置 concurrencyLevel 使得緩存支持并發的寫入和讀取
Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(3).concurrencyLevel(Runtime.getRuntime().availableProcessors()).build();更新鎖定
GuavaCache提供了一個refreshAfterWrite定時刷新數據的配置項,如果經過一定時間沒有更新或覆蓋,則會在下一次獲取該值的時候,會在后臺異步去刷新緩存
刷新時只有一個請求回源取數據,其他請求會阻塞(block)在一個固定時間段,如果在該時間段內沒有獲得新值則返回舊值。
@Testpublic void refresh() throws InterruptedException, ExecutionException {LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder().maximumSize(3).concurrencyLevel(Runtime.getRuntime().availableProcessors()).refreshAfterWrite(3, TimeUnit.SECONDS).build(new CacheLoader<Integer, Integer>() {@Overridepublic Integer load(Integer key) throws Exception {return sourceMap.get(key);}});cache.get(1);System.out.println("第一次取值: " + cache.getIfPresent(1));sourceMap.put(1, 10);Thread.sleep(5000);System.out.println("第二次取值: " + cache.getIfPresent(1));}應用場景:accesstoken token失效 從公網拿token 采用更新鎖定
GuavaCache高級實戰之疑難問題
GuavaCache會oom(內存溢出)嗎
會,當我們設置緩存永不過期(或者很長),緩存的對象不限個數(或者很大)時,比如:
Cache<String, String> cache = CacheBuilder.newBuilder() .expireAfterWrite(100000, TimeUnit.SECONDS) .build();解決方案:緩存時間設置相對小些,使用弱引用方式存儲對象
GuavaCache緩存到期就會立即清除嗎
不是的,GuavaCache是在每次進行緩存操作的時候,如get()或者put()的時候,判斷緩存是否過期。
一個如果一個對象放入緩存以后,不在有任何緩存操作(包括對緩存其他key的操作),那么該緩存不
會主動過期的。
GuavaCache如何找出最久未使用的數據
用accessQueue,這個隊列是按照LRU的順序放的緩存對象(ReferenceEntry)的,會把訪問過的對象放在隊列的最后。
并且可以很方便的更新和刪除鏈表中的節點,因為每次訪問的時候都可能需要更新鏈表,放入到鏈表的尾部。
這樣,每次從access中拿出的頭結點就是最久未使用的。
對應的writeQueue用來保存最久未更新的緩存隊列,實現方式和accessQueue一樣。
其他比較好的文章推薦:
中文教程
Guava總結好的博客
總結
以上是生活随笔為你收集整理的本地缓存之Guava简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中String、StringBu
- 下一篇: 通过jquery回显操作(笔记)