最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

輕松了解java中Caffeine高性能緩存庫(kù)

 更新時(shí)間:2021年08月17日 17:28:43   作者:碼農(nóng)熊貓  
本文我們將學(xué)習(xí)了解到用于Java的高性能緩存庫(kù)Caffeine,其使用Window TinyLfu清理策略,提供最佳的命中率

輕松lCaffeine

1、依賴

我們需要將Caffeine依賴添加到我們的pom.xml中:

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

2、寫入緩存

讓我們關(guān)注Caffeine的三種緩存寫入策略:手動(dòng)、同步加載和異步加載。

首先,讓我們編寫一個(gè)類,作為要存儲(chǔ)在緩存中的值的類型:

class DataObject {
    private final String data;

    private static int objectCounter = 0;
    // standard constructors/getters
    
    public static DataObject get(String data) {
        objectCounter++;
        return new DataObject(data);
    }
}

 2.1、手動(dòng)寫入

在此策略中,我們手動(dòng)將值寫入緩存并稍后讀取它們。

我們先初始化緩存:

Cache<String, DataObject> cache = Caffeine.newBuilder()
  .expireAfterWrite(1, TimeUnit.MINUTES)
  .maximumSize(100)
  .build();

現(xiàn)在,我們可以使用getIfPresent方法從緩存中獲取一些值。如果緩存中不存在該值,則此方法將返回null:

我們可以使用put方法手動(dòng)寫入緩存:

cache.put(key, dataObject);
dataObject = cache.getIfPresent(key);

assertNotNull(dataObject);

我們還可以使用get方法獲取值,該方法接受一個(gè)函數(shù)和一個(gè)鍵作為參數(shù)。如果緩存中不存在該鍵,則此函數(shù)將用于提供兜底值,該值將在執(zhí)行后寫入緩存:

dataObject = cache
  .get(key, k -> DataObject.get("Data for A"));

assertNotNull(dataObject);
assertEquals("Data for A", dataObject.getData());

這個(gè)GET方法執(zhí)行是原子性的。這意味著即使多個(gè)線程同時(shí)請(qǐng)求該值,執(zhí)行只會(huì)進(jìn)行一次。這就是為什么使用get比getIfPresent更好。

有時(shí)我們需要手動(dòng)使一些緩存的值失效:

cache.invalidate(key);
dataObject = cache.getIfPresent(key);

assertNull(dataObject);

2.2、同步加載

這種加載緩存的方法需要一個(gè)Function,用于初始化寫入值,類似于手動(dòng)寫入策略的get方法,讓我們看看如何使用它。

首先,我們需要初始化我們的緩存:

現(xiàn)在我們可以使用get方法讀取值:

DataObject dataObject = cache.get(key);

assertNotNull(dataObject);
assertEquals("Data for " + key, dataObject.getData());

我們還可以使用getAll方法獲取一組值:

Map<String, DataObject> dataObjectMap 
  = cache.getAll(Arrays.asList("A", "B", "C"));

assertEquals(3, dataObjectMap.size());

值從傳遞給build方法的底層后端初始化Function中讀取到,這樣就可以使用緩存作為訪問(wèn)值的主要入口了。

2.3、異步加載

此策略的工作原理與前一個(gè)相同,但是會(huì)異步執(zhí)行操作并返回一個(gè)CompletableFuture來(lái)保存實(shí)際的值:

AsyncLoadingCache<String, DataObject> cache = Caffeine.newBuilder()
  .maximumSize(100)
  .expireAfterWrite(1, TimeUnit.MINUTES)
  .buildAsync(k -> DataObject.get("Data for " + k));

 我們可以以相同的方式使用get和getAll方法,考慮到它們的返回是CompletableFuture:

String key = "A";

cache.get(key).thenAccept(dataObject -> {
    assertNotNull(dataObject);
    assertEquals("Data for " + key, dataObject.getData());
});

cache.getAll(Arrays.asList("A", "B", "C"))
  .thenAccept(dataObjectMap -> assertEquals(3, dataObjectMap.size()));

CompletableFuture具有很多有用的API,您可以在本文中閱讀更多相關(guān)信息。

3、緩存值的清理

Caffeine有三種緩存值的清理策略:基于大小、基于時(shí)間和基于引用。

3.1、基于大小的清理

這種類型的清理設(shè)計(jì)為在超出緩存配置的大小限制時(shí)發(fā)生清理。有兩種獲取大小的方法——計(jì)算緩存中的對(duì)象數(shù),或者獲取它們的權(quán)重。

讓我們看看如何計(jì)算緩存中的對(duì)象數(shù)。緩存初始化時(shí),其大小為零:

LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
  .maximumSize(1)
  .build(k -> DataObject.get("Data for " + k));

assertEquals(0, cache.estimatedSize());

當(dāng)我們添加一個(gè)值時(shí),大小明顯增加:

cache.get("A");

assertEquals(1, cache.estimatedSize());

 我們可以將第二個(gè)值添加到緩存中,這會(huì)導(dǎo)致刪除第一個(gè)值:

cache.get("B");
cache.cleanUp();

assertEquals(1, cache.estimatedSize());

值得一提的是,我們?cè)讷@取緩存大小之前調(diào)用了cleanUp方法。這是因?yàn)榫彺媲謇硎钱惒綀?zhí)行的,該方法有助于等待清理完成。

我們還可以傳入一個(gè)weigher的Function來(lái)定義緩存大小的獲?。?/p>

LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
  .maximumWeight(10)
  .weigher((k,v) -> 5)
  .build(k -> DataObject.get("Data for " + k));

assertEquals(0, cache.estimatedSize());

cache.get("A");
assertEquals(1, cache.estimatedSize());

cache.get("B");
assertEquals(2, cache.estimatedSize());

當(dāng)權(quán)重超過(guò) 10 時(shí),這些值將從緩存中刪除:

cache.get("C");
cache.cleanUp();

assertEquals(2, cache.estimatedSize());

3.2、基于時(shí)間的清理

這種清理策略基于條目的過(guò)期時(shí)間,分為三種:

訪問(wèn)后過(guò)期——自上次讀取或?qū)懭胍詠?lái),條目在經(jīng)過(guò)某段時(shí)間后過(guò)期
寫入后過(guò)期——自上次寫入以來(lái),條目在經(jīng)過(guò)某段時(shí)間后過(guò)期
自定義策略——由Expiry的實(shí)現(xiàn)來(lái)為每個(gè)條目單獨(dú)計(jì)算到期時(shí)間
讓我們使用expireAfterAccess方法配置訪問(wèn)后過(guò)期策略:

LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
  .expireAfterAccess(5, TimeUnit.MINUTES)
  .build(k -> DataObject.get("Data for " + k));

要配置寫入后過(guò)期策略,我們使用expireAfterWrite方法:

cache = Caffeine.newBuilder()
  .expireAfterWrite(10, TimeUnit.SECONDS)
  .weakKeys()
  .weakValues()
  .build(k -> DataObject.get("Data for " + k));

要初始化自定義策略,我們需要實(shí)現(xiàn)Expiry接口:

cache = Caffeine.newBuilder().expireAfter(new Expiry<String, DataObject>() {
    @Override
    public long expireAfterCreate(
      String key, DataObject value, long currentTime) {
        return value.getData().length() * 1000;
    }
    @Override
    public long expireAfterUpdate(
      String key, DataObject value, long currentTime, long currentDuration) {
        return currentDuration;
    }
    @Override
    public long expireAfterRead(
      String key, DataObject value, long currentTime, long currentDuration) {
        return currentDuration;
    }
}).build(k -> DataObject.get("Data for " + k));

 3.3、基于引用的清理

我們可以配置我們的緩存,允許緩存的鍵或值或二者一起的垃圾收集。為此,我們需要為鍵和值配置WeakReference的使用,并且我們可以配置SoftReference僅用于值的垃圾收集。

WeakReference的使用允許在沒有對(duì)對(duì)象的任何強(qiáng)引用時(shí)對(duì)對(duì)象進(jìn)行垃圾回收。SoftReference允許基于JVM的全局LRU(最近最少使用)策略對(duì)對(duì)象進(jìn)行垃圾回收??梢栽诖颂幷业接嘘P(guān)Java中引用的更多詳細(xì)信息。

我們使用Caffeine.weakKeys()、Caffeine.weakValues()和Caffeine.softValues()來(lái)啟用每個(gè)選項(xiàng):

LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
  .expireAfterWrite(10, TimeUnit.SECONDS)
  .weakKeys()
  .weakValues()
  .build(k -> DataObject.get("Data for " + k));

cache = Caffeine.newBuilder()
  .expireAfterWrite(10, TimeUnit.SECONDS)
  .softValues()
  .build(k -> DataObject.get("Data for " + k));

 

4、緩存刷新

可以將緩存配置為在定義的時(shí)間段后自動(dòng)刷新條目。讓我們看看如何使用refreshAfterWrite方法做到這一點(diǎn):

Caffeine.newBuilder()
  .refreshAfterWrite(1, TimeUnit.MINUTES)
  .build(k -> DataObject.get("Data for " + k));

在這里,我們應(yīng)該明白expireAfter和refreshAfter的一個(gè)區(qū)別:當(dāng)請(qǐng)求過(guò)期條目時(shí),執(zhí)行會(huì)阻塞,直到build函數(shù)計(jì)算出新值。但是如果該條目符合刷新條件,則緩存將返回一個(gè)舊值并異步重新加載該值。

5、統(tǒng)計(jì)

Caffeine提供了一種記錄緩存使用統(tǒng)計(jì)信息的方法:

LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
  .maximumSize(100)
  .recordStats()
  .build(k -> DataObject.get("Data for " + k));
cache.get("A");
cache.get("A");

assertEquals(1, cache.stats().hitCount());
assertEquals(1, cache.stats().missCount());

到此這篇關(guān)于輕松了解java中Caffeine高性能緩存庫(kù)的文章就介紹到這了,更多相關(guān)java Caffeine緩存庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java web xml文件讀取解析方式

    Java web xml文件讀取解析方式

    這篇文章主要介紹了Java web xml文件讀取解析方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 一篇文章帶你入門Java封裝

    一篇文章帶你入門Java封裝

    Java面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(tài)。下面對(duì)三大特性之一封裝進(jìn)行了總結(jié),需要的朋友可以參考下,希望能給你帶來(lái)幫助
    2021-08-08
  • Java內(nèi)存區(qū)域和內(nèi)存模型講解

    Java內(nèi)存區(qū)域和內(nèi)存模型講解

    今天小編就為大家分享一篇關(guān)于Java內(nèi)存區(qū)域和內(nèi)存模型講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • 詳解SpringBoot之集成Spring AOP

    詳解SpringBoot之集成Spring AOP

    本篇文章主要介紹了詳解SpringBoot之集成Spring AOP,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Java常用對(duì)象操作工具代碼實(shí)例

    Java常用對(duì)象操作工具代碼實(shí)例

    這篇文章主要介紹了Java常用對(duì)象操作工具代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • SpringBoot Validation入?yún)⑿r?yàn)國(guó)際化的項(xiàng)目實(shí)踐

    SpringBoot Validation入?yún)⑿r?yàn)國(guó)際化的項(xiàng)目實(shí)踐

    在Spring Boot中,可以使用Validation和國(guó)際化來(lái)實(shí)現(xiàn)對(duì)入?yún)⒌男r?yàn),本文就來(lái)介紹一下SpringBoot Validation入?yún)⑿r?yàn)國(guó)際化,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • Java實(shí)現(xiàn)HDFS文件上傳下載

    Java實(shí)現(xiàn)HDFS文件上傳下載

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)HDFS文件上傳下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • java判定數(shù)組或集合是否存在某個(gè)元素的實(shí)例

    java判定數(shù)組或集合是否存在某個(gè)元素的實(shí)例

    下面小編就為大家?guī)?lái)一篇java判定數(shù)組或集合是否存在某個(gè)元素的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • Mybatis-plus多數(shù)據(jù)源配置的兩種方式總結(jié)

    Mybatis-plus多數(shù)據(jù)源配置的兩種方式總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Mybatis-plus中多數(shù)據(jù)源配置的兩種方式,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-10-10
  • Java?Collection接口中的常用方法總結(jié)

    Java?Collection接口中的常用方法總結(jié)

    這篇文章將大概用代碼案例簡(jiǎn)單總結(jié)一下?Collection?接口中的一些方法,我們會(huì)以他的實(shí)現(xiàn)類?Arraylist?為例創(chuàng)建對(duì)象。快一起來(lái)看看吧
    2022-12-12

最新評(píng)論

黄大仙区| 桂东县| 三明市| 花莲市| 琼海市| 资中县| 玉门市| 台北县| 若羌县| 吴堡县| 榆中县| 湟源县| 万荣县| 衡水市| 吴旗县| 丰台区| 阳曲县| 密云县| 吉隆县| 古蔺县| 全州县| 京山县| 新源县| 顺昌县| 宕昌县| 南部县| 奉化市| 宜兰县| 栾川县| 鄯善县| 德庆县| 四子王旗| 治多县| 宁远县| 邢台县| 惠州市| 耿马| 马关县| 建德市| 江安县| 商都县|