在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Caffeine學習筆記

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-10-25 17:20 ? 次閱讀

作者:京東工業 孫磊

一、認識Caffeine

1、Caffeine是什么?

Caffeine是一個基于Java8開發的提供了近乎最佳命中率的高性能的緩存庫, 也是SpringBoot內置的本地緩存實現。

2、Caffeine提供了靈活的構造器去創建一個擁有下列特性的緩存:

?自動加載條目到緩存中,可選異步方式

?可以基于大小剔除

?可以設置過期時間,時間可以從上次訪問或上次寫入開始計算

?異步刷新

?keys自動包裝在弱引用中

?values自動包裝在弱引用或軟引用中

?條目剔除通知

?緩存訪問統計

3、核心類和參數

核心工具類:Caffeine是創建高性能緩存的基類。

核心參數:

maximumSize:緩存最大值

maximumWeight:緩存最大權重,權重和最大值不能同時設置

initialCapacity:緩存初始容量

expireAfterWriteNanos:在寫入多少納秒沒更新后過期

expireAfterAccessNanos:在訪問多少納秒沒更新后過期

refreshAfterWriteNanos:寫入多少納秒沒更新后更新

二、數據加載

Caffeine提供了四種緩存添加策略

1、手動加載

public static void demo() {
    Cache cache =
            Caffeine.newBuilder()
                    .expireAfterAccess(Duration.ofMinutes(1))
                    .maximumSize(100)
                    .recordStats()
                    .build();

    // 插入數據
    cache.put("a", "a");
    // 查詢某個key,如果沒有返回空
    String a = cache.getIfPresent("a");
    System.out.println(a);
    // 查找緩存,如果緩存不存在則生成緩存元素,  如果無法生成則返回null
    String b = cache.get("b", k -> {
        System.out.println("begin query ..." + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        System.out.println("end query ...");
        return UUID.randomUUID().toString();
    });
    System.out.println(b);

    // 移除一個緩存元素
    cache.invalidate("a");
}

2、自動加載

public static void demo() {

        LoadingCache loadingCache = Caffeine.newBuilder()
                .maximumSize(100)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build(new CacheLoader() {

                    @Nullable
                    @Override
                    public Object load(@NonNull Object key) throws Exception {
                        return createExpensiveValue();
                    }

                    @Override
                    public @NonNull Map loadAll(@NonNull Iterable keys) throws Exception {

                        if (keys == null) {
                            return Collections.emptyMap();
                        }
                        Map map = new HashMap();
                        for (Object key : keys) {
                            map.put((String) key, createExpensiveValue());
                        }
                        return map;
                    }
                });

        // 查找緩存,如果緩存不存在則生成緩存元素,  如果無法生成則返回null
        String a = loadingCache.get("a");
        System.out.println(a);

        // 批量查找緩存,如果緩存不存在則生成緩存元素
        Set keys = new HashSet();
        keys.add("a");
        keys.add("b");
        Map allValues = loadingCache.getAll(keys);
        System.out.println(allValues);
    }

    private static String createExpensiveValue() {
        {
            System.out.println("begin query ..." + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("end query ...");
            return UUID.randomUUID().toString();
        }
    }

一個LoadingCache是Cache附加一個CacheLoader能力之后的緩存實現。

getAll方法中,將會對每個key調用一次CacheLoader.load來生成元素,當批量查詢效率更高的時候,你可以自定義loadAll方法實現。

3、手動異步加載

public static void demo() throws ExecutionException, InterruptedException {
    AsyncCache asyncCache = Caffeine.newBuilder()
            .maximumSize(100)
            .buildAsync();

    // 添加或者更新一個緩存元素
    asyncCache.put("a",CompletableFuture.completedFuture("a"));

    // 查找一個緩存元素, 沒有查找到的時候返回null
    CompletableFuture a = asyncCache.getIfPresent("a");
    System.out.println(a.get());

    // 查找緩存元素,如果不存在,則異步生成
    CompletableFuture completableFuture = asyncCache.get("b", k ->createExpensiveValue("b"));

    System.out.println(completableFuture.get());
    
    // 移除一個緩存元素
    asyncCache.synchronous().invalidate("a");
    System.out.println(asyncCache.getIfPresent("a"));
}

private static String createExpensiveValue(String key) {
    {
        System.out.println("begin query ..." + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        System.out.println("end query ...");
        return UUID.randomUUID().toString();
    }
}

一個`AsyncCache`是 `Cache`的一個變體,`AsyncCache`提供了在 Executor上生成緩存元素并返回 CompletableFuture的能力。這給出了在當前流行的響應式編程模型中利用緩存的能力。

synchronous()方法給 Cache提供了阻塞直到異步緩存生成完畢的能力。

異步緩存默認的線程池實現是 ForkJoinPool.commonPool() ,你也可以通過覆蓋并實現 `Caffeine.executor(Executor)`方法來自定義你的線程池選擇。

4、自動異步加載

public static void demo() throws ExecutionException, InterruptedException {

    AsyncLoadingCache cache = Caffeine.newBuilder()
            .maximumSize(10_000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            // 你可以選擇: 去異步的封裝一段同步操作來生成緩存元素
            //.buildAsync(key -> createExpensiveValue(key));
            // 你也可以選擇: 構建一個異步緩存元素操作并返回一個future
            .buildAsync((key, executor) ->createExpensiveValueAsync(key, executor));

    // 查找緩存元素,如果其不存在,將會異步進行生成
    CompletableFuture a = cache.get("a");
    System.out.println(a.get());

    // 批量查找緩存元素,如果其不存在,將會異步進行生成
    Set keys = new HashSet();
    keys.add("a");
    keys.add("b");
    CompletableFuture> values = cache.getAll(keys);
    System.out.println(values.get());
}

private static String createExpensiveValue(String key) {
    {
        System.out.println("begin query ..." + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        System.out.println("end query ...");
        return UUID.randomUUID().toString();
    }
}

private static CompletableFuture createExpensiveValueAsync(String key, Executor executor) {
    {
        System.out.println("begin query ..." + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
            executor.execute(()-> System.out.println("async create value...."));
        } catch (InterruptedException e) {
        }
        System.out.println("end query ...");
        return CompletableFuture.completedFuture(UUID.randomUUID().toString());
    }
}

一個 AsyncLoadingCache是一個 AsyncCache 加上 AsyncCacheLoader能力的實現。

在需要同步的方式去生成緩存元素的時候,CacheLoader是合適的選擇。而在異步生成緩存的場景下, AsyncCacheLoader則是更合適的選擇并且它會返回一個 CompletableFuture。

三、驅除策略

Caffeine 提供了三種驅逐策略,分別是基于容量,基于時間和基于引用三種類型;還提供了手動移除方法和監聽器。

1、基于容量

// 基于緩存容量大小,緩存中個數進行驅逐
Cache cache =
        Caffeine.newBuilder()
                .maximumSize(100)
                .recordStats()
                .build();

// 基于緩存的權重進行驅逐
AsyncCache asyncCache = Caffeine.newBuilder()
                .maximumWeight(10)
                .buildAsync();

2、基于時間

// 基于固定時間
Cache cache =
        Caffeine.newBuilder()
//距離上次訪問后一分鐘刪除
                .expireAfterAccess(Duration.ofMinutes(1))
                .recordStats()
                .build();

Cache cache =
                Caffeine.newBuilder()
// 距離上次寫入一分鐘后刪除
                        .expireAfterWrite(Duration.ofMinutes(1))
                        .recordStats()
                        .build();
// 基于不同的過期驅逐策略
Cache expire =
                Caffeine.newBuilder()
                        .expireAfter(new Expiry() {
                            @Override
                            public long expireAfterCreate(@NonNull String key, @NonNull String value, long currentTime) {
                                return LocalDateTime.now().plusMinutes(5).getSecond();
                            }

                            @Override
                            public long expireAfterUpdate(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) {
                                return currentDuration;
                            }

                            @Override
                            public long expireAfterRead(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) {
                                return currentDuration;
                            }
                        })
                        .recordStats()
                        .build();

Caffeine提供了三種方法進行基于時間的驅逐:

?expireAfterAccess(long, TimeUnit): 一個值在最近一次訪問后,一段時間沒訪問時被淘汰。

?expireAfterWrite(long, TimeUnit): 一個值在初次創建或最近一次更新后,一段時間后被淘汰。

?expireAfter(Expiry): 一個值將會在指定的時間后被認定為過期項。

3、基于引用

java對象引用匯總表:

?

?

?

// 當key和緩存元素都不再存在其他強引用的時候驅逐
LoadingCache weak = Caffeine.newBuilder()
        .weakKeys()
        .weakValues()
        .build(k ->createExpensiveValue());

// 當進行GC的時候進行驅逐
LoadingCache soft = Caffeine.newBuilder()
        .softValues()
        .build(k ->createExpensiveValue());

weakKeys:使用弱引用存儲key時,當沒有其他的強引用時,則會被垃圾回收器回收。

weakValues:使用弱引用存儲value時,當沒有其他的強引用時,則會被垃圾回收器回收。

softValues:使用軟引用存儲key時,當沒有其他的強引用時,內存不足時會被回收。

4、手動移除

Cache cache =
                Caffeine.newBuilder()
                        .expireAfterWrite(Duration.ofMinutes(1))
                        .recordStats()
                        .build();
// 單個刪除
cache.invalidate("a");
// 批量刪除
Set keys = new HashSet();
keys.add("a");
keys.add("b");
cache.invalidateAll(keys);

// 失效所有key
cache.invalidateAll();

任何時候都可以手動刪除,不用等到驅逐策略生效。

5、移除監聽器

Cache cache =
        Caffeine.newBuilder()
                .expireAfterWrite(Duration.ofMinutes(1))
                .recordStats()
                .evictionListener(new RemovalListener() {
                    @Override
                    public void onRemoval(@Nullable Object key, @Nullable Object value, @NonNull RemovalCause cause) {
                        System.out.println("element evict cause" + cause.name());
                    }
                })
                .removalListener(new RemovalListener() {
                    @Override
                    public void onRemoval(@Nullable Object key, @Nullable Object value, @NonNull RemovalCause cause) {
                        System.out.println("element removed cause" + cause.name());
                    }
                }).build();

你可以為你的緩存通過Caffeine.removalListener(RemovalListener)方法定義一個移除監聽器在一個元素被移除的時候進行相應的操作。這些操作是使用 Executor異步執行的,其中默認的 Executor 實現是 ForkJoinPool.commonPool()并且可以通過覆蓋Caffeine.executor(Executor)方法自定義線程池的實現。

注意:Caffeine.evictionListener(RemovalListener)。這個監聽器將在 RemovalCause.wasEvicted()為 true 的時候被觸發。

6、驅逐原因匯總

EXPLICIT:如果原因是這個,那么意味著數據被我們手動的remove掉了 REPLACED:就是替換了,也就是put數據的時候舊的數據被覆蓋導致的移除 COLLECTED:這個有歧義點,其實就是收集,也就是垃圾回收導致的,一般是用弱引用或者軟引用會導致這個情況 EXPIRED:數據過期,無需解釋的原因。 SIZE:個數超過限制導致的移除

四、緩存統計

Caffeine通過使用Caffeine.recordStats()方法可以打開數據收集功能,可以幫助優化緩存使用。

// 緩存訪問統計
CacheStats stats = cache.stats();
System.out.println("stats.hitCount():"+stats.hitCount());//命中次數
System.out.println("stats.hitRate():"+stats.hitRate());//緩存命中率
System.out.println("stats.missCount():"+stats.missCount());//未命中次數
System.out.println("stats.missRate():"+stats.missRate());//未命中率
System.out.println("stats.loadSuccessCount():"+stats.loadSuccessCount());//加載成功的次數
System.out.println("stats.loadFailureCount():"+stats.loadFailureCount());//加載失敗的次數,返回null
System.out.println("stats.loadFailureRate():"+stats.loadFailureRate());//加載失敗的百分比
System.out.println("stats.totalLoadTime():"+stats.totalLoadTime());//總加載時間,單位ns
System.out.println("stats.evictionCount():"+stats.evictionCount());//驅逐次數
System.out.println("stats.evictionWeight():"+stats.evictionWeight());//驅逐的weight值總和
System.out.println("stats.requestCount():"+stats.requestCount());//請求次數
System.out.println("stats.averageLoadPenalty():"+stats.averageLoadPenalty());//單次load平均耗時

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    19

    文章

    2982

    瀏覽量

    106304
  • 計算
    +關注

    關注

    2

    文章

    452

    瀏覽量

    39085
  • 緩存
    +關注

    關注

    1

    文章

    244

    瀏覽量

    26913
收藏 0人收藏

    評論

    相關推薦

    PADS應用學習筆記

    本內容提供了PADS應用學習筆記,PADS2007學習及Power PCb使用經驗
    發表于 11-24 10:42 ?1.1w次閱讀

    Allegro學習筆記

    Allegro學習筆記 不收積分,需要的看下
    發表于 11-23 17:41 ?0次下載

    網友學習CCS的筆記

    網友學習CCS的筆記,有需要的朋友下來看看
    發表于 05-06 15:32 ?0次下載

    模擬電路學習筆記

    模擬電子的相關知識學習教材資料——模擬電路學習筆記
    發表于 09-20 16:10 ?0次下載

    PADS_2007學習筆記

    PADS_2007學習筆記
    發表于 01-16 13:54 ?18次下載

    Ansoft學習筆記

    ansoft學習筆記與常見問題
    發表于 03-23 10:24 ?0次下載

    Java設計模式學習筆記

    Java設計模式學習筆記
    發表于 09-08 10:15 ?5次下載
    Java設計模式<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    基于msp430學習筆記

    基于msp430學習筆記
    發表于 10-12 09:00 ?16次下載
    基于msp430<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    ARM學習筆記

    ARM學習筆記
    發表于 10-13 14:28 ?3次下載
    ARM<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    機器學習的個人學習筆記

    本文檔的主要內容詳細介紹的是機器學習的個人學習筆記免費下載。
    發表于 03-01 09:28 ?23次下載
    機器<b class='flag-5'>學習</b>的個人<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    Altera FPGA CPLD學習筆記

    Altera FPGA CPLD學習筆記(肇慶理士電源技術有限)-Altera FPGA CPLD學習筆記? ? ? ? ? ? ? ? ?
    發表于 09-18 10:54 ?83次下載
    Altera FPGA CPLD<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    學習筆記】單片機匯編學習

    學習筆記】單片機匯編學習
    發表于 11-14 18:21 ?15次下載
    【<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>】單片機匯編<b class='flag-5'>學習</b>

    Can通信接口學習筆記

    Can通信接口學習筆記
    發表于 12-08 16:36 ?26次下載
    Can通信接口<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    Sentaurus TCAD學習筆記

    半導體仿真Sentaurus TCAD 學習筆記,僅供學習
    發表于 08-07 14:54 ?5次下載

    Allegro學習筆記.zip

    Allegro學習筆記
    發表于 12-30 09:19 ?7次下載

    電子發燒友

    中國電子工程師最喜歡的網站

    • 2931785位工程師會員交流學習
    • 獲取您個性化的科技前沿技術信息
    • 參加活動獲取豐厚的禮品
    主站蜘蛛池模板: 3p性小说 | 天天操人人| 很黄的网站在线观看 | 高清视频在线播放 | 国产一级特黄高清在线大片 | 五月婷色| 国产特黄一级毛片特黄 | 18女人毛片水真多免费 | 五月亭亭免费高清在线 | 国产精品青草久久 | 亚洲你懂的| 国内精品手机在线观看视频 | 免费三级毛片 | 国模私拍一区二区三区 | 国产1024一区二区你懂的 | 深夜一级毛片 | 国产成人精品日本亚洲网站 | 日韩电影中文字幕 | 欧美一级片网站 | 国产特级毛片aaaaaa毛片 | 好爽的视频黄 | h免费在线观看 | 欧美人与动欧交视频 | 狠狠操夜夜爱 | 男人日女人免费视频 | 午夜色在线 | 亚洲精品网站日本xxxxxxx | 国产亚洲一区二区三区在线 | 欧美一级高清免费播放 | 爱爱的免费视频 | 亚洲视频国产 | 四虎影视最新 | 日日爽夜夜 | 好爽好深太大了再快一点 | 欧美成人天天综合天天在线 | 在线视频影院 | 看黄网站在线观看 | 亚洲国产精品乱码在线观看97 | 你懂的视频在线观看资源 | 色老头性xxxx老头视频 | 欧美三级视频网站 |