精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

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

3天內(nèi)不再提示

Caffeine學(xué)習(xí)筆記

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

作者:京東工業(yè) 孫磊

一、認識Caffeine

1、Caffeine是什么?

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

2、Caffeine提供了靈活的構(gòu)造器去創(chuàng)建一個擁有下列特性的緩存:

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

?可以基于大小剔除

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

?異步刷新

?keys自動包裝在弱引用中

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

?條目剔除通知

?緩存訪問統(tǒng)計

3、核心類和參數(shù)

核心工具類:Caffeine是創(chuàng)建高性能緩存的基類。

核心參數(shù):

maximumSize:緩存最大值

maximumWeight:緩存最大權(quán)重,權(quán)重和最大值不能同時設(shè)置

initialCapacity:緩存初始容量

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

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

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

二、數(shù)據(jù)加載

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

1、手動加載

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

    // 插入數(shù)據(jù)
    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能力之后的緩存實現(xiàn)。

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

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的能力。這給出了在當前流行的響應(yīng)式編程模型中利用緩存的能力。

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

異步緩存默認的線程池實現(xiàn)是 ForkJoinPool.commonPool() ,你也可以通過覆蓋并實現(xiàn) `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));
            // 你也可以選擇: 構(gòu)建一個異步緩存元素操作并返回一個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能力的實現(xiàn)。

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

三、驅(qū)除策略

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

1、基于容量

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

// 基于緩存的權(quán)重進行驅(qū)逐
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();
// 基于不同的過期驅(qū)逐策略
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提供了三種方法進行基于時間的驅(qū)逐:

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

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

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

3、基于引用

java對象引用匯總表:

?

?

?

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

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

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

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

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

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();

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

5、移除監(jiān)聽器

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)方法定義一個移除監(jiān)聽器在一個元素被移除的時候進行相應(yīng)的操作。這些操作是使用 Executor異步執(zhí)行的,其中默認的 Executor 實現(xiàn)是 ForkJoinPool.commonPool()并且可以通過覆蓋Caffeine.executor(Executor)方法自定義線程池的實現(xiàn)。

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

6、驅(qū)逐原因匯總

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

四、緩存統(tǒng)計

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

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

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2960

    瀏覽量

    104562
  • 計算
    +關(guān)注

    關(guān)注

    2

    文章

    446

    瀏覽量

    38739
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    233

    瀏覽量

    26649
收藏 人收藏

    評論

    相關(guān)推薦

    PADS應(yīng)用學(xué)習(xí)筆記

    本內(nèi)容提供了PADS應(yīng)用學(xué)習(xí)筆記,PADS2007學(xué)習(xí)及Power PCb使用經(jīng)驗
    發(fā)表于 11-24 10:42 ?1.1w次閱讀

    Allegro學(xué)習(xí)筆記

    Allegro學(xué)習(xí)筆記 不收積分,需要的看下
    發(fā)表于 11-23 17:41 ?0次下載

    網(wǎng)友學(xué)習(xí)CCS的筆記

    網(wǎng)友學(xué)習(xí)CCS的筆記,有需要的朋友下來看看
    發(fā)表于 05-06 15:32 ?0次下載

    模擬電路學(xué)習(xí)筆記

    模擬電子的相關(guān)知識學(xué)習(xí)教材資料——模擬電路學(xué)習(xí)筆記
    發(fā)表于 09-20 16:10 ?0次下載

    PADS_2007學(xué)習(xí)筆記

    PADS_2007學(xué)習(xí)筆記
    發(fā)表于 01-16 13:54 ?18次下載

    Ansoft學(xué)習(xí)筆記

    ansoft學(xué)習(xí)筆記與常見問題
    發(fā)表于 03-23 10:24 ?0次下載

    Java設(shè)計模式學(xué)習(xí)筆記

    Java設(shè)計模式學(xué)習(xí)筆記
    發(fā)表于 09-08 10:15 ?5次下載
    Java設(shè)計模式<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>

    基于msp430學(xué)習(xí)筆記

    基于msp430學(xué)習(xí)筆記
    發(fā)表于 10-12 09:00 ?16次下載
    基于msp430<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>

    ARM學(xué)習(xí)筆記

    ARM學(xué)習(xí)筆記
    發(fā)表于 10-13 14:28 ?3次下載
    ARM<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>

    機器學(xué)習(xí)的個人學(xué)習(xí)筆記

    本文檔的主要內(nèi)容詳細介紹的是機器學(xué)習(xí)的個人學(xué)習(xí)筆記免費下載。
    發(fā)表于 03-01 09:28 ?22次下載
    機器<b class='flag-5'>學(xué)習(xí)</b>的個人<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>

    Altera FPGA CPLD學(xué)習(xí)筆記

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

    學(xué)習(xí)筆記】單片機匯編學(xué)習(xí)

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

    Can通信接口學(xué)習(xí)筆記

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

    Sentaurus TCAD學(xué)習(xí)筆記

    半導(dǎo)體仿真Sentaurus TCAD 學(xué)習(xí)筆記,僅供學(xué)習(xí)
    發(fā)表于 08-07 14:54 ?4次下載

    Allegro學(xué)習(xí)筆記.zip

    Allegro學(xué)習(xí)筆記
    發(fā)表于 12-30 09:19 ?6次下載