亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring內(nèi)存緩存Caffeine的基本使用教程分享

 更新時(shí)間:2023年03月24日 09:07:54   作者:一灰灰  
Caffeine作為當(dāng)下本地緩存的王者被大量的應(yīng)用再實(shí)際的項(xiàng)目中,可以有效的提高服務(wù)吞吐率、qps,降低rt,本文就來簡單介紹下Caffeine的使用姿勢吧

項(xiàng)目配置

依賴

首先搭建一個(gè)標(biāo)準(zhǔn)的SpringBoot項(xiàng)目工程,相關(guān)版本以及依賴如下

本項(xiàng)目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA進(jìn)行開發(fā)

<dependencies>
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
    </dependency>
</dependencies>

使用實(shí)例

引入上面的jar包之后,就可以進(jìn)入caffeine的使用環(huán)節(jié)了;我們主要依照官方wiki來進(jìn)行演練

Home zh CN · ben-manes/caffeine Wiki

caffeine提供了四種緩存策略,主要是基于手動(dòng)添加/自動(dòng)添加,同步/異步來進(jìn)行區(qū)分

其基本使用姿勢于Guava差不多

1.手動(dòng)加載

private LoadingCache<String, Integer> autoCache;
private AtomicInteger idGen;
public CacheService() {
      // 手動(dòng)緩存加載方式
      idGen = new AtomicInteger(100);
      uidCache = Caffeine.newBuilder()
              // 設(shè)置寫入后五分鐘失效
              .expireAfterWrite(5, TimeUnit.MINUTES)
              // 設(shè)置最多的緩存數(shù)量
              .maximumSize(100)
              .build();
}

1.1 三種失效策略

注意參數(shù)設(shè)置,我們先看一下失效策略,共有下面幾種

權(quán)重:

  • maximumSize: 基于容量策略,當(dāng)緩存內(nèi)元素個(gè)數(shù)超過時(shí),通過基于就近度和頻率的算法來驅(qū)逐掉不會(huì)再被使用到的元素
  • maximumWeight: 基于權(quán)重的容量策略,主要應(yīng)用于緩存中的元素存在不同的權(quán)重場景

時(shí)間:

  • expireAfterAccess: 基于訪問時(shí)間
  • expireAfterWrite: 基于寫入時(shí)間
  • expireAfter: 可以根據(jù)讀更新寫入來調(diào)整有效期

引用:

  • weakKeys: 保存的key為弱引用
  • weakValues: 保存的value會(huì)使用弱引用
  • softValues: 保存的value使用軟引用

弱引用:這允許在GC的過程中,當(dāng)沒有被任何強(qiáng)引用指向的時(shí)候去將緩存元素回收

軟引用:在GC過程中被軟引用的對象將會(huì)被通過LRU算法回收

1.2 緩存增刪查姿勢

接下來我們看一下手動(dòng)方式的使用

public void getUid(String session) {
    // 重新再取一次,這次應(yīng)該就不是重新初始化了
    Integer uid = uidCache.getIfPresent(session);
    System.out.println("查看緩存! 當(dāng)沒有的時(shí)候返回的是 uid: " + uid);

    // 第二個(gè)參數(shù)表示當(dāng)不存在時(shí),初始化一個(gè),并寫入緩存中
    uid = uidCache.get(session, (key) -> 10);
    System.out.println("初始化一個(gè)之后,返回的是: " + uid);

    // 移除緩存
    uidCache.invalidate(session);

    // 手動(dòng)添加一個(gè)緩存
    uidCache.put(session + "_2", 11);

    // 查看所有的額緩存
    Map map = uidCache.asMap();
    System.out.println("total: " + map);

    // 干掉所有的緩存
    uidCache.invalidateAll();
}

查詢緩存&添加緩存

  • getIfPresent(key): 不存在時(shí),返回null
  • get(key, (key) -> {value初始化策略}): 不存在時(shí),會(huì)根據(jù)第二個(gè)lambda表達(dá)式來寫入數(shù)據(jù),這個(gè)就表示的是手動(dòng)加載緩存
  • asMap: 獲取緩存所有數(shù)據(jù)

添加緩存

  • put(key, val): 主動(dòng)添加緩存

清空緩存

  • invalidate: 主動(dòng)移除緩存
  • invalidateAll: 失效所有緩存

執(zhí)行完畢之后,輸出日志:

查看緩存! 當(dāng)沒有的時(shí)候返回的是 uid: null
初始化一個(gè)之后,返回的是: 10
total: {02228476-bcd9-412d-b437-bf0092c4a5f6_2=11}

2.自動(dòng)加載

在創(chuàng)建的時(shí)候,就指定緩存未命中時(shí)的加載規(guī)則

// 在創(chuàng)建時(shí),自動(dòng)指定加載規(guī)則
private LoadingCache<String, Integer> autoCache;
private AtomicInteger idGen;

public CacheService() {
    // 手動(dòng)緩存加載方式
    idGen = new AtomicInteger(100);
    autoCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .build(new CacheLoader<String, Integer>() {
                @Override
                public @Nullable Integer load(@NonNull String key) throws Exception {
                    return idGen.getAndAdd(1);
                }
            });
}

它的配置,與前面介紹的一致;主要的區(qū)別點(diǎn)在于build時(shí),確定緩存值的獲取方式

2.1 緩存使用姿勢

public void autoGetUid(String session) {
    Integer uid = autoCache.getIfPresent(session);
    System.out.println("自動(dòng)加載,沒有時(shí)返回: " + uid);

    uid = autoCache.get(session);
    System.out.println("自動(dòng)加載,沒有時(shí)自動(dòng)加載一個(gè): " + uid);

    // 批量查詢
    List<String> keys = Arrays.asList(session, session + "_1");
    Map<String, Integer> map = autoCache.getAll(keys);
    System.out.println("批量獲取,一個(gè)存在一個(gè)不存在時(shí):" + map);

    // 手動(dòng)加一個(gè)
    autoCache.put(session + "_2", 11);
    Map total = autoCache.asMap();
    System.out.println("total: " + total);
}

與前面的區(qū)別在于獲取緩存值的方式

  • get(key): 不用傳第二個(gè)參數(shù),直接傳key獲取對應(yīng)的緩存值,如果沒有自動(dòng)加載數(shù)據(jù)
  • getAll(keys): 可以批量獲取數(shù)據(jù),若某個(gè)key不再緩存中,會(huì)自動(dòng)加載;在里面的則直接使用緩存的

實(shí)際輸出結(jié)果如下

自動(dòng)加載,沒有時(shí)返回: null
自動(dòng)加載,沒有時(shí)自動(dòng)加載一個(gè): 100
批量獲取,一個(gè)存在一個(gè)不存在時(shí):{02228476-bcd9-412d-b437-bf0092c4a5f6=100, 02228476-bcd9-412d-b437-bf0092c4a5f6_1=101}
total: {02228476-bcd9-412d-b437-bf0092c4a5f6_2=11, 02228476-bcd9-412d-b437-bf0092c4a5f6_1=101, 02228476-bcd9-412d-b437-bf0092c4a5f6=100}

3.異步手動(dòng)加載

異步,主要是值在獲取換粗內(nèi)容時(shí),采用的異步策略;使用與前面沒有什么太大差別

// 手動(dòng)異步加載緩存
private AsyncCache<String, Integer> asyncUidCache;

public CacheService() {
    asyncUidCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .buildAsync();
}

3.1 緩存使用姿勢

public void asyncGetUid(String session) throws ExecutionException, InterruptedException {
    // 重新再取一次,這次應(yīng)該就不是重新初始化了
    CompletableFuture<Integer> uid = asyncUidCache.getIfPresent(session);
    System.out.println("查看緩存! 當(dāng)沒有的時(shí)候返回的是 uid: " + (uid == null ? "null" : uid.get()));

    // 第二個(gè)參數(shù)表示當(dāng)不存在時(shí),初始化一個(gè),并寫入緩存中
    uid = asyncUidCache.get(session, (key) -> 10);
    System.out.println("初始化一個(gè)之后,返回的是: " + uid.get());

    // 手動(dòng)塞入一個(gè)緩存
    asyncUidCache.put(session + "_2", CompletableFuture.supplyAsync(() -> 12));

    // 移除緩存
    asyncUidCache.synchronous().invalidate(session);
    // 查看所有的額緩存
    System.out.println("print total cache:");
    for (Map.Entry<String, CompletableFuture<Integer>> sub : asyncUidCache.asMap().entrySet()) {
        System.out.println(sub.getKey() + "==>" + sub.getValue().get());
    }
    System.out.println("total over");
}
  • getIfPresent: 存在時(shí)返回CompletableFuture,不存在時(shí)返回null,因此注意npe的問題
  • get(key, Function<>): 第二個(gè)參數(shù)表示加載數(shù)據(jù)的邏輯
  • put(key, CompletableFuture<>): 手動(dòng)加入緩存,注意這里也不是直接加一個(gè)具體的value到緩存
  • synchronous().invalidate() : 同步清除緩存
  • getAll: 一次獲取多個(gè)緩存,同樣的是在緩存的取緩存,不在的根據(jù)第二個(gè)傳參進(jìn)行加載

與前面相比,使用姿勢差不多,唯一注意的是,獲取的并不是直接的結(jié)果,而是CompletableFuture,上面執(zhí)行之后的輸出如下:

查看緩存! 當(dāng)沒有的時(shí)候返回的是 uid: null
初始化一個(gè)之后,返回的是: 10
print total cache:
5dd53310-aec7-42a5-957e-f7492719c29d_2==>12
total over

4.異步自動(dòng)加載

在定義緩存時(shí),就指定了緩存不存在的加載邏輯;與第二個(gè)相比區(qū)別在于這里是異步加載數(shù)據(jù)到緩存中

private AtomicInteger idGen;
// 自動(dòng)異步加載緩存
private AsyncLoadingCache<String, Integer> asyncAutoCache;
public CacheService() {
  idGen = new AtomicInteger(100);
  asyncAutoCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .buildAsync(new CacheLoader<String, Integer>() {
                @Override
                public @Nullable Integer load(@NonNull String key) throws Exception {
                    return idGen.getAndAdd(1);
                }
            });
}

4.1 緩存使用姿勢

public void asyncAutoGetUid(String session) {
    try {
        CompletableFuture<Integer> uid = asyncAutoCache.getIfPresent(session);
        System.out.println("自動(dòng)加載,沒有時(shí)返回: " + (uid == null ? "null" : uid.get()));

        uid = asyncAutoCache.get(session);
        System.out.println("自動(dòng)加載,沒有時(shí)自動(dòng)加載一個(gè): " + uid.get());

        // 批量查詢
        List<String> keys = Arrays.asList(session, session + "_1");
        CompletableFuture<Map<String, Integer>> map = asyncAutoCache.getAll(keys);
        System.out.println("批量獲取,一個(gè)存在一個(gè)不存在時(shí):" + map.get());
        
        // 手動(dòng)加一個(gè)
        asyncAutoCache.put(session + "_2", CompletableFuture.supplyAsync(() -> 11));
        
        // 查看所有的額緩存
        System.out.println("print total cache:");
        for (Map.Entry<String, CompletableFuture<Integer>> sub : asyncAutoCache.asMap().entrySet()) {
            System.out.println(sub.getKey() + "==>" + sub.getValue().get());
        }
        System.out.println("total over");

        // 清空所有緩存
        asyncAutoCache.synchronous().invalidateAll();
      } catch (Exception e) {
        e.printStackTrace();
    }
}

輸出:

自動(dòng)加載,沒有時(shí)返回: null
自動(dòng)加載,沒有時(shí)自動(dòng)加載一個(gè): 102
批量獲取,一個(gè)存在一個(gè)不存在時(shí):{5dd53310-aec7-42a5-957e-f7492719c29d=102, 5dd53310-aec7-42a5-957e-f7492719c29d_1=103}
print total cache:
5dd53310-aec7-42a5-957e-f7492719c29d_2==>11
5dd53310-aec7-42a5-957e-f7492719c29d_1==>103
5dd53310-aec7-42a5-957e-f7492719c29d==>102
total over

以上就是Spring內(nèi)存緩存Caffeine的基本使用教程分享的詳細(xì)內(nèi)容,更多關(guān)于Spring內(nèi)存緩存Caffeine的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java 詳解單向加密--MD5、SHA和HMAC及簡單實(shí)現(xiàn)實(shí)例

    Java 詳解單向加密--MD5、SHA和HMAC及簡單實(shí)現(xiàn)實(shí)例

    這篇文章主要介紹了Java 詳解單向加密--MD5、SHA和HMAC及簡單實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 解決idea更新maven倉庫的圖文教程

    解決idea更新maven倉庫的圖文教程

    這篇文章主要介紹了解決idea更新maven倉庫的圖文教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 淺談SpringBoot項(xiàng)目如何讓前端開發(fā)提高效率(小技巧)

    淺談SpringBoot項(xiàng)目如何讓前端開發(fā)提高效率(小技巧)

    這篇文章主要介紹了淺談SpringBoot項(xiàng)目如何讓前端開發(fā)提高效率(小技巧),主要介紹了Swagger和Nginx提高效率的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Java并發(fā)編程之淺談ReentrantLock

    Java并發(fā)編程之淺談ReentrantLock

    今天帶大家學(xué)習(xí)Java并發(fā)編程的相關(guān)知識(shí),文中對Java ReentrantLock作了非常詳細(xì)的圖文示例,對正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Java集合Iterator迭代的實(shí)現(xiàn)方法

    Java集合Iterator迭代的實(shí)現(xiàn)方法

    這篇文章主要介紹了Java集合Iterator迭代接口的實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒家,對Java 結(jié)合iterator知識(shí)感興趣的朋友一起看看吧
    2016-08-08
  • Spring boot定時(shí)任務(wù)的原理及動(dòng)態(tài)創(chuàng)建詳解

    Spring boot定時(shí)任務(wù)的原理及動(dòng)態(tài)創(chuàng)建詳解

    這篇文章主要給大家介紹了關(guān)于Spring boot定時(shí)任務(wù)的原理及動(dòng)態(tài)創(chuàng)建的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • java同步之volatile解析

    java同步之volatile解析

    volatile可以說是Java虛擬機(jī)提供的最輕量級的同步機(jī)制了,了解volatile的語義對理解多線程的特性具有很重要的意義,下面小編帶大家一起學(xué)習(xí)一下
    2019-05-05
  • Spring Boot集成教程之異步調(diào)用Async

    Spring Boot集成教程之異步調(diào)用Async

    在項(xiàng)目中,當(dāng)訪問其他人的接口較慢或者做耗時(shí)任務(wù)時(shí),不想程序一直卡在耗時(shí)任務(wù)上,想程序能夠并行執(zhí)行,我們可以使用多線程來并行的處理任務(wù),也可以使用spring提供的異步處理方式@Async。需要的朋友們下面來一起看看吧。
    2018-03-03
  • Springboot項(xiàng)目中定時(shí)任務(wù)的四種實(shí)現(xiàn)方式詳解

    Springboot項(xiàng)目中定時(shí)任務(wù)的四種實(shí)現(xiàn)方式詳解

    Spring的@Scheduled注解是一種非常簡單和便捷的實(shí)現(xiàn)定時(shí)任務(wù)的方式,通過在方法上添加@Scheduled注解,我們可以指定方法在特定的時(shí)間間隔或固定的時(shí)間點(diǎn)執(zhí)行,本文給大家介紹Springboot項(xiàng)目中定時(shí)任務(wù)的四種實(shí)現(xiàn)方式,感興趣的的朋友一起看看b
    2024-02-02
  • Spring Boot2.3 新特性分層JAR的使用

    Spring Boot2.3 新特性分層JAR的使用

    這篇文章主要介紹了Spring Boot2.3 新特性分層JAR的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06

最新評論