日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > Caffe >内容正文

Caffe

本地缓存Caffeine

發布時間:2025/3/8 Caffe 112 豆豆
生活随笔 收集整理的這篇文章主要介紹了 本地缓存Caffeine 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Caffeine

說起Guava Cache,很多人都不會陌生,它是Google Guava工具包中的一個非常方便易用的本地化緩存實現,基于LRU算法實現,支持多種緩存過期策略。由于Guava的大量使用,Guava Cache也得到了大量的應用。但是,Guava Cache的性能一定是最好的嗎?也許,曾經,它的性能是非常不錯的。但所謂長江后浪推前浪,總會有更加優秀的技術出現。今天,我就來介紹一個比Guava Cache性能更高的緩存框架:Caffeine。

Tips: Spring5(SpringBoot2)開始用Caffeine取代guava.詳見官方信息SPR-13797 jira.spring.io/browse/SPR-…

什么時候用

  • 愿意消耗一些內存空間來提升速度
  • 預料到某些鍵會被多次查詢
  • 緩存中存放的數據總量不會超出內存容量
  • 性能

    由圖可以看出,Caffeine不論讀還是寫的效率都遠高于其他緩存。

    這里只列出部分性能比較,詳細請看官方官方 github.com/ben-manes/c…

    依賴

    我們需要在 pom.xml 中添加 caffeine 依賴:

    版本問題參考mvnrepository.com/artifact/co…

    <dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>2.7.0</version> </dependency> 復制代碼

    新建對象

    // 1、最簡單 Cache<String, Object> cache = Caffeine.newBuilder().build(); // 2、真實使用過程中我們需要自己配置參數。這里只列舉部分,具體請看下面列表 Cache<String, Object> cache = Caffeine.newBuilder().initialCapacity(2)//初始大小.maximumSize(2)//最大數量.expireAfterWrite(3, TimeUnit.SECONDS)//過期時間.build(); 復制代碼

    參數含義

    • initialCapacity: 初始的緩存空間大小
    • maximumSize: 緩存的最大數量
    • maximumWeight: 緩存的最大權重
    • expireAfterAccess: 最后一次讀或寫操作后經過指定時間過期
    • expireAfterWrite: 最后一次寫操作后經過指定時間過期
    • refreshAfterWrite: 創建緩存或者最近一次更新緩存后經過指定時間間隔,刷新緩存
    • weakKeys: 打開key的弱引用
    • weakValues:打開value的弱引用
    • softValues:打開value的軟引用
    • recordStats:開發統計功能

    注意: expireAfterWrite和expireAfterAccess同時存在時,以expireAfterWrite為準。 maximumSize和maximumWeight不可以同時使用

    異步

    AsyncCache<Object, Object> asyncCache = Caffeine.newBuilder().buildAsync(); 復制代碼

    解釋

    A semi-persistent mapping from keys to values. Cache entries are manually added using {@link #get(Object, Function)} or {@link #put(Object, CompletableFuture)}, and are stored in the cache until either evicted or manually invalidated. Implementations of this interface are expected to be thread-safe, and can be safely accessed by multiple concurrent threads. 復制代碼

    添加數據

    Caffeine 為我們提供了三種填充策略:

    手動、同步和異步

    手動添加

    很簡單的

    public static void main(String[] args) {Cache<String, String> cache = Caffeine.newBuilder().build();cache.put("hello", "world");System.out.println(cache.getIfPresent("hello")); } 復制代碼

    自動添加1(自定義添加函數)

    Cache<String, String> cache = Caffeine.newBuilder().build();// 1.如果緩存中能查到,則直接返回 // 2.如果查不到,則從我們自定義的getValue方法獲取數據,并加入到緩存中 cache.get("hello", new Function<String, String>() {@Overridepublic String apply(String k) {return getValue(k);} }); System.out.println(cache.getIfPresent("hello")); }// 緩存中找不到,則會進入這個方法。一般是從數據庫獲取內容 private static String getValue(String k) {return k + ":value"; 復制代碼

    // 這種寫法可以簡化成下面Lambda表達式 cache.get("hello", new Function<String, String>() { @Override public String apply(String k) { return getValue(k); } }); // 可以簡寫為 cache.get("hello", k -> getValue(k));

    自動添加2(初始添加)

    和上面方法一樣,只不過這個是在新建對象的時候添加

    LoadingCache<String, String> loadingCache = Caffeine.newBuilder().build(new CacheLoader<String, String>() {@Overridepublic String load(String k) {return getValue(k);}}); // 同樣可簡化為下面這樣 LoadingCache<String, String> loadingCache2 = Caffeine.newBuilder().build(k -> getValue(k)); 復制代碼

    過期策略

    Caffeine提供三類驅逐策略:

  • 基于大小(size-based)
  • 基于時間(time-based)
  • 基于引用(reference-based)
  • 1、大小

    Cache<String, String> cache = Caffeine.newBuilder().maximumSize(3).build(); cache.put("key1", "value1"); cache.put("key2", "value2"); cache.put("key3", "value3"); cache.put("key4", "value4"); cache.put("key5", "value5"); cache.cleanUp(); System.out.println(cache.getIfPresent("key1")); System.out.println(cache.getIfPresent("key2")); System.out.println(cache.getIfPresent("key3")); System.out.println(cache.getIfPresent("key4")); System.out.println(cache.getIfPresent("key5")); 復制代碼

    輸出結果

    null value2 null value4 value5 復制代碼

    1、淘汰2個

    2、淘汰并不是按照先后順序,內部有自己的算法

    2、時間

    Caffeine提供了三種定時驅逐策略:

    • expireAfterAccess(long, TimeUnit):在最后一次訪問或者寫入后開始計時,在指定的時間后過期。假如一直有請求訪問該key,那么這個緩存將一直不會過期。
    • expireAfterWrite(long, TimeUnit): 在最后一次寫入緩存后開始計時,在指定的時間后過期。
    • expireAfter(Expiry): 自定義策略,過期時間由Expiry實現獨自計算。

    緩存的刪除策略使用的是惰性刪除和定時刪除。這兩個刪除策略的時間復雜度都是O(1)。

    expireAfterWrite

    Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(3, TimeUnit.SECONDS).build(); cache.put("key1", "value1"); cache.put("key2", "value2"); cache.put("key3", "value3"); cache.put("key4", "value4"); cache.put("key5", "value5"); System.out.println(cache.getIfPresent("key1")); System.out.println(cache.getIfPresent("key2")); Thread.sleep(3*1000); System.out.println(cache.getIfPresent("key3")); System.out.println(cache.getIfPresent("key4")); System.out.println(cache.getIfPresent("key5")); 復制代碼

    結果

    value1 value2 null null null 復制代碼

    例子2

    Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(3, TimeUnit.SECONDS).build(); cache.put("key1", "value1"); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("key1")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("key1")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("key1")); 復制代碼

    結果

    value1 value1 null 復制代碼

    expireAfterAccess

    Access就是讀和寫

    Cache<String, String> cache = Caffeine.newBuilder().expireAfterAccess(3, TimeUnit.SECONDS).build(); cache.put("key1", "value1"); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("key1")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("key1")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("key1")); Thread.sleep(3*1000); System.out.println(cache.getIfPresent("key1")); 復制代碼

    結果

    value1 value1 value1 null 復制代碼

    讀和寫都沒有的情況下,3秒后才過期

    也可以同時用expireAfterAccess和expireAfterWrite方法指定過期時間,這時只要對象滿足兩者中的一個條件就會被自動過期刪除。

    expireAfter 和 refreshAfter 之間的區別

    • expireAfter 條件觸發后,新的值更新完成前,所有請求都會被阻塞,更新完成后其他請求才能訪問這個值。這樣能確保獲取到的都是最新的值,但是有性能損失。
    • refreshAfter 條件觸發后,新的值更新完成前也可以訪問,不會被阻塞,只是獲取的是舊的數據。更新結束后,獲取的才是新的數據。有可能獲取到臟數據。

    3、引用

    • Caffeine.weakKeys() 使用弱引用存儲key。如果沒有其他地方對該key有強引用,那么該緩存就會被垃圾回收器回收。
    • Caffeine.weakValues() 使用弱引用存儲value。如果沒有其他地方對該value有強引用,那么該緩存就會被垃圾回收器回收。
    • Caffeine.softValues() 使用軟引用存儲value。
    Cache<String, Object> cache = Caffeine.newBuilder().weakValues().build(); Object value1 = new Object(); Object value2 = new Object(); cache.put("key1", value1); cache.put("key2", value2);value2 = new Object(); // 原對象不再有強引用 System.gc(); System.out.println(cache.getIfPresent("key1")); System.out.println(cache.getIfPresent("key2")); 復制代碼

    結果

    java.lang.Object@7a4f0f29 null 復制代碼

    解釋:當給value2引用賦值一個新的對象之后,就不再有任何一個強引用指向原對象。System.gc()觸發垃圾回收后,原對象就被清除了。

    簡單回顧下Java中的四種引用

    Java4種引用的級別由高到低依次為:強引用 > 軟引用 > 弱引用 > 虛引用

    引用類型被垃圾回收時間用途生存時間
    強引用從來不會對象的一般狀態JVM停止運行時終止
    軟引用在內存不足時對象緩存內存不足時終止
    弱引用在垃圾回收時對象緩存GC運行后終止
    虛引用UnknownUnknownUnknown

    顯式刪除緩存

    除了通過上面的緩存淘汰策略刪除緩存,我們還可以手動的刪除

    // 1、指定key刪除 cache.invalidate("key1"); // 2、批量指定key刪除 List<String> list = new ArrayList<>(); list.add("key1"); list.add("key2"); cache.invalidateAll(list);//批量清除list中全部key對應的記錄 // 3、刪除全部 cache.invalidateAll(); 復制代碼

    淘汰、移除監聽器

    可以為緩存對象添加一個移除監聽器,這樣當有記錄被刪除時可以感知到這個事件。

    Cache<String, String> cache = Caffeine.newBuilder().expireAfterAccess(3, TimeUnit.SECONDS).removalListener(new RemovalListener<Object, Object>() {@Overridepublic void onRemoval(@Nullable Object key, @Nullable Object value, @NonNull RemovalCause cause) {System.out.println("key:" + key + ",value:" + value + ",刪除原因:" + cause);}}).expireAfterWrite(1, TimeUnit.SECONDS).build(); cache.put("key1", "value1"); cache.put("key2", "value2"); cache.invalidate("key1"); Thread.sleep(2 * 1000); cache.cleanUp(); 復制代碼

    結果

    key:key1,value:value1,刪除原因:EXPLICIT key:key2,value:value2,刪除原因:EXPIRED 復制代碼

    統計

    Cache<String, String> cache = Caffeine.newBuilder().maximumSize(3).recordStats().build(); cache.put("key1", "value1"); cache.put("key2", "value2"); cache.put("key3", "value3"); cache.put("key4", "value4");cache.getIfPresent("key1"); cache.getIfPresent("key2"); cache.getIfPresent("key3"); cache.getIfPresent("key4"); cache.getIfPresent("key5"); cache.getIfPresent("key6"); System.out.println(cache.stats()); 復制代碼

    結果

    CacheStats{hitCount=4, missCount=2, loadSuccessCount=0, loadFailureCount=0, totalLoadTime=0, evictionCount=0, evictionWeight=0} 復制代碼

    除了結果輸出的內容,CacheStats還可以獲取如下數據。

    參考

    oopsguy.com/2017/10/25/… juejin.im/post/5b8df6… www.jianshu.com/p/9a80c662d… www.sohu.com/a/235729991… www.cnblogs.com/yueshutong/… blog.csdn.net/qq_38974634… blog.csdn.net/qq_32867467… blog.csdn.net/grafx/artic… ifeve.com/google-guav…

    總結

    以上是生活随笔為你收集整理的本地缓存Caffeine的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日本在线小视频 | 一级毛片黄片 | 欧美黑人激情 | 狠狠干美女| 动漫艳母在线观看 | 久久人妻少妇嫩草av无码专区 | 亚洲第一免费 | 亚洲一区二区麻豆 | 亚洲久久影院 | 在线观看91av | 欧美色图影院 | 911色| 欧洲精品无码一区二区 | 人人亚洲| jizz日韩| 黄色片视频网站 | 日韩av不卡在线播放 | 爱乃なみ加勒比在线播放 | 日本不卡一区二区在线观看 | 久久成年视频 | 日韩av在线播放一区 | 超碰伊人| 国产黄色一级大片 | 美女视频一区 | 少妇太爽了在线观看 | 亚洲操| 日本大尺度做爰呻吟 | 精品视频在线观看免费 | 美女久久久久久久久久 | 亚洲综合在线播放 | 日韩一本在线 | 国产亚洲欧美日韩高清 | 国产自在线 | 岛国av动作片 | 高清一二三区 | 国产精品久久久久久久久久久新郎 | 美女狂揉羞羞的视频 | 看久久 | 天天干天天爽天天操 | 色94色欧美| jizz中国少妇高潮出水 | 一本色道久久综合亚洲精品按摩 | 久操亚洲| 亚洲综合精品国产一区二区三区 | 免费成人激情视频 | 黄色美女av | 有码av在线 | av动漫天堂| 日鲁鲁 | 刘亦菲久久免费一区二区 | 国产初高中真实精品视频 | 大陆一级片 | 九九久久久 | 欧美日韩亚洲激情 | 久久久精品日本 | www.黄色片| 日韩精品一区二区三区中文字幕 | 久久久欧洲 | 成人高潮片免费视频 | 一级少妇片 | 麻豆成人精品 | 波多野结衣有码 | 老妇荒淫牲艳史 | av毛片在线 | 国产精品黄在线观看 | 97精品一区二区视频在线观看 | 99久久精品国产一区二区成人 | 黄色免费91 | 热久久国产精品 | 色噜噜成人 | 欧洲亚洲另类 | 亚洲图片在线观看 | 国产午夜精品一区二区三区四区 | 国产欧美日韩综合 | 国产婷婷一区二区 | 黄av资源| 亚洲免费一区二区 | 麻豆精品 | 九九精品免费 | 依人成人综合网 | 青青导航 | 国产亚洲女人久久久久毛片 | 超碰成人在线观看 | a毛片| 在线草| 91精品国产视频 | 人人妻人人玩人人澡人人爽 | 粗大黑人巨茎大战欧美成人免费看 | 成年人爱爱视频 | 少妇福利视频 | 人妻久久久一区二区三区 | 国产成人免费看 | 久久精品国产免费 | 少妇av一区二区 | 欧美又大又硬又粗bbbbb | 麻豆91精品91久久久 | 色综合久久久久 | 人妻一区二区三区在线 | 探花一区 |