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

一文詳解Caffeine緩存庫的常用功能與使用指南

 更新時間:2025年07月31日 08:56:20   作者:越重天  
Caffeine作為新一代高性能Java緩存庫,在并發(fā)場景下展現(xiàn)出卓越表現(xiàn),本文將介紹Caffeine緩存庫的常用功能使用介紹,希望對大家有所幫助

Caffeine作為新一代高性能Java緩存庫,在并發(fā)場景下展現(xiàn)出卓越表現(xiàn)。它通過創(chuàng)新的W-TinyLFU淘汰算法實現(xiàn)高達99%的命中率,并采用無鎖設計使吞吐量較傳統(tǒng)方案提升5-10倍。該庫提供靈活的緩存管理能力:支持基于時間(寫入/訪問過期)、數(shù)量或權(quán)重的淘汰策略;允許為單個Key設置專屬過期時間;獨創(chuàng)的異步刷新機制能在不阻塞請求的情況下更新數(shù)據(jù)。開發(fā)者可通過簡潔的鏈式API配置內(nèi)存控制、加載邏輯和事件監(jiān)聽,輕松構(gòu)建高并發(fā)低延遲的智能緩存系統(tǒng)。其與Guava Cache兼容的接口設計,更使遷移成本降至最低。

以下是 Caffeine 緩存庫的常用功能使用介紹,涵蓋基礎操作、過期策略、淘汰配置等核心功能:

一、基礎緩存操作

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

// 1. 創(chuàng)建緩存實例
Cache<String, Object> cache = Caffeine.newBuilder()
        .build();

// 2. 添加數(shù)據(jù)
cache.put("key1", "value1");

// 3. 獲取數(shù)據(jù)(手動)
Object value = cache.getIfPresent("key1"); // 存在返回value,否則null

// 4. 刪除數(shù)據(jù)
cache.invalidate("key1");
cache.invalidateAll(); // 清空緩存

二、自動加載緩存(推薦)

LoadingCache<String, Object> cache = Caffeine.newBuilder()
        .build(key -> {
            // 緩存未命中時自動執(zhí)行的加載邏輯
            return fetchFromDB(key); // 自定義數(shù)據(jù)庫加載方法
        });

// 自動加載數(shù)據(jù)(緩存未命中時執(zhí)行build中的邏輯)
Object value = cache.get("user_123");

三、過期策略配置

1. 全局過期策略

Cache<String, Object> cache = Caffeine.newBuilder()
        // 寫入后30分鐘過期
        .expireAfterWrite(30, TimeUnit.MINUTES)
        
        // 最后訪問后15分鐘過期
        .expireAfterAccess(15, TimeUnit.MINUTES)
        
        // 自定義過期策略(按需實現(xiàn))
        .expireAfter(new Expiry<String, Object>() {
            public long expireAfterCreate(String key, Object value, long currentTime) {
                return TimeUnit.MINUTES.toNanos(10); // 創(chuàng)建后10分鐘過期
            }
            public long expireAfterUpdate(String key, Object value, long currentTime, long currentDuration) {
                return currentDuration; // 更新后不改變過期時間
            }
            public long expireAfterRead(String key, Object value, long currentTime, long currentDuration) {
                return currentDuration; // 讀取后不改變過期時間
            }
        })
        .build();

2. 單Key過期(高級用法)

// 創(chuàng)建支持變長過期的緩存
Cache<String, Object> cache = Caffeine.newBuilder()
        .expireAfter(new Expiry<String, Object>() {
            // ...實現(xiàn)同上
        })
        .build();

// 為特定Key設置不同過期時間
cache.policy().expireVariably().ifPresent(policy -> {
    policy.put("hot_key", "value", 2, TimeUnit.HOURS);  // 2小時
    policy.put("cold_key", "value", 10, TimeUnit.MINUTES); // 10分鐘
});

四、淘汰策略配置

Cache<String, Object> cache = Caffeine.newBuilder()
        // 基于數(shù)量淘汰(最多1000個條目)
        .maximumSize(1000)
        
        // 基于權(quán)重淘汰(需實現(xiàn)Weigher)
        .maximumWeight(10_000)
        .weigher((String key, Object value) -> {
            // 自定義權(quán)重計算邏輯
            if (value instanceof String) return ((String) value).length();
            if (value instanceof List) return ((List<?>) value).size();
            return 1;
        })
        
        // 基于引用回收(謹慎使用)
        .weakKeys()      // 弱引用Key
        .weakValues()    // 弱引用Value
        .softValues()    // 軟引用Value
        .build();

五、刷新策略(優(yōu)于純過期)

LoadingCache<String, Object> cache = Caffeine.newBuilder()
        // 寫入后1分鐘可刷新(不阻塞讀取,異步刷新舊值)
        .refreshAfterWrite(1, TimeUnit.MINUTES)
        .build(key -> fetchFromDB(key));

六、監(jiān)聽器與統(tǒng)計

Cache<String, Object> cache = Caffeine.newBuilder()
        // 移除監(jiān)聽器
        .removalListener((String key, Object value, RemovalCause cause) -> {
            System.out.printf("Key %s was removed (%s)%n", key, cause);
        })
        // 啟用統(tǒng)計
        .recordStats()
        .build();

// 獲取統(tǒng)計信息
CacheStats stats = cache.stats();
System.out.printf("Hit Rate: %.2f%%, Loads: %d%n",
        stats.hitRate() * 100, stats.loadCount());

七、異步操作

// 1. 異步緩存
AsyncLoadingCache<String, Object> asyncCache = Caffeine.newBuilder()
        .buildAsync(key -> fetchFromDB(key));

// 獲取數(shù)據(jù)(返回CompletableFuture)
CompletableFuture<Object> future = asyncCache.get("key1");

// 2. 同步視圖操作
Object value = asyncCache.synchronous().get("key1");

八、最佳實踐配置模板

LoadingCache<String, Object> optimalCache = Caffeine.newBuilder()
        // 容量控制
        .maximumSize(10_000)
        
        // 過期策略
        .expireAfterWrite(30, TimeUnit.MINUTES)
        
        // 刷新策略
        .refreshAfterWrite(5, TimeUnit.MINUTES)
        
        // 統(tǒng)計和監(jiān)聽
        .recordStats()
        .removalListener((key, value, cause) -> 
            logRemoval(key, cause))
        
        // 自動加載
        .build(key -> fetchFromDB(key));

九、基于Caffeine實現(xiàn)的動態(tài)緩存

我們有時候需要這樣一種場景:當用戶請求某個key的時候,該緩存自動從數(shù)據(jù)庫去加載,就是注冊一個數(shù)據(jù)庫加載器(自己實現(xiàn)),當獲取不到該key時,自動走數(shù)據(jù)庫查詢,然后存入該key中。當往caffeine緩存中插入一個key后,如果緩存沒有,則自動存入,并自動同步到數(shù)據(jù)庫中,當刪除一個key,或key過期后,自動從數(shù)據(jù)庫同步刪除。

以下是簡單的實現(xiàn)流程:

import com.github.benmanes.caffeine.cache.*;
import java.util.concurrent.TimeUnit;

public class DynamicCache<K, V> {

    private final Cache<K, V> cache;
    private final DataLoader<K, V> dataLoader;
    private final DataSynchronizer<K, V> dataSynchronizer;

    public DynamicCache(DataLoader<K, V> dataLoader, DataSynchronizer<K, V> dataSynchronizer) {
        this.dataLoader = dataLoader;
        this.dataSynchronizer = dataSynchronizer;
        
        this.cache = Caffeine.newBuilder()
                // 配置緩存策略(按需設置)
                .expireAfterWrite(30, TimeUnit.MINUTES)  // 30分鐘過期
                .maximumSize(1000)                      // 最大緩存項
                // 注冊移除監(jiān)聽器(用于刪除數(shù)據(jù)庫數(shù)據(jù))
                .removalListener((K key, V value, RemovalCause cause) -> {
                    if (cause.wasEvicted()) {  // 僅處理過期或容量剔除
                        dataSynchronizer.deleteFromDatabase(key);
                    }
                })
                // 注冊加載器(用于緩存未命中時從DB加載)
                .build(key -> {
                    V value = dataLoader.loadFromDatabase(key);
                    if (value == null) throw new Exception("Key not found");
                    return value;
                });
    }

    // 獲取數(shù)據(jù)(自動加載)
    public V get(K key) {
        return cache.get(key, k -> {
            V value = dataLoader.loadFromDatabase(k);
            if (value == null) throw new RuntimeException("Data not found");
            return value;
        });
    }

    // 添加/更新數(shù)據(jù)(同步到數(shù)據(jù)庫)
    public void put(K key, V value) {
        // 先同步到數(shù)據(jù)庫
        dataSynchronizer.saveToDatabase(key, value);
        // 再更新緩存
        cache.put(key, value);
    }

    // 刪除數(shù)據(jù)(同步刪除數(shù)據(jù)庫)
    public void delete(K key) {
        // 先刪除數(shù)據(jù)庫數(shù)據(jù)
        dataSynchronizer.deleteFromDatabase(key);
        // 再使緩存失效
        cache.invalidate(key);
    }

    // 數(shù)據(jù)庫加載器接口
    public interface DataLoader<K, V> {
        V loadFromDatabase(K key);
    }

    // 數(shù)據(jù)庫同步器接口
    public interface DataSynchronizer<K, V> {
        void saveToDatabase(K key, V value);
        void deleteFromDatabase(K key);
    }
}

上述接口使用示例:

// 1. 實現(xiàn)數(shù)據(jù)庫操作接口
DynamicCache.DataLoader<String, User> loader = key -> 
    jdbcTemplate.queryForObject("SELECT * FROM users WHERE id=?", User.class, key);

DynamicCache.DataSynchronizer<String, User> synchronizer = new DynamicCache.DataSynchronizer<>() {
    @Override
    public void saveToDatabase(String key, User value) {
        jdbcTemplate.update("INSERT OR REPLACE INTO users (id, name) VALUES (?, ?)", 
                           key, value.getName());
    }

    @Override
    public void deleteFromDatabase(String key) {
        jdbcTemplate.update("DELETE FROM users WHERE id=?", key);
    }
};

// 2. 創(chuàng)建緩存實例
DynamicCache<String, User> userCache = new DynamicCache<>(loader, synchronizer);

// 3. 使用緩存
// 自動加載(緩存未命中時從DB加載)
User user = userCache.get("user123");  

// 添加/更新(同步到DB)
userCache.put("user456", new User("Alice"));

// 刪除(同步刪除DB數(shù)據(jù))
userCache.delete("user789");

關鍵特性說明:

1.自動加載

  • 當調(diào)用 get() 方法且緩存未命中時,自動通過 DataLoader 從數(shù)據(jù)庫加載
  • 加載成功后自動填充緩存

2.寫穿透

put() 操作時:

  • 先通過 DataSynchronizer 保存到數(shù)據(jù)庫
  • 再更新緩存

保證數(shù)據(jù)庫與緩存的數(shù)據(jù)一致性

3.刪除同步

delete() 操作時:

  • 先刪除數(shù)據(jù)庫數(shù)據(jù)
  • 再使緩存失效

緩存過期/淘汰時:

通過 RemovalListener 自動觸發(fā)數(shù)據(jù)庫刪除

4.緩存配置

  • 可自定義過期時間(expireAfterWrite
  • 可設置最大容量(maximumSize
  • 支持其他Caffeine特性(刷新策略、弱引用等)

關鍵特性對比表

功能配置方法適用場景
寫入過期expireAfterWrite()數(shù)據(jù)更新頻率低的場景
訪問過期expireAfterAccess()讀多寫少的場景
自適應過期expireAfter(Expiry)需要動態(tài)過期時間的場景
數(shù)量淘汰maximumSize()通用場景
權(quán)重淘汰maximumWeight() + weigher()緩存對象大小差異大的場景
異步刷新refreshAfterWrite()高并發(fā)讀取+后臺更新
弱/軟引用weakKeys()/softValues()內(nèi)存敏感型應用

注意事項

1.刷新 vs 過期

  • 刷新 (refreshAfterWrite) 異步更新舊值,不阻塞請求
  • 過期 (expireAfterWrite) 會阻塞請求直到新值加載完成

2.權(quán)重計算

  • 確保 weigher 計算快速(納秒級)
  • 權(quán)重總和不超過 maximumWeight

3.過期時間精度

.scheduler(Scheduler.systemScheduler())

默認時間精度≈1秒,需要毫秒級精度可配置:

4.并發(fā)加載控制

  • 相同key并發(fā)請求時,只有一個線程執(zhí)行加載
  • 可通過 executor() 指定自定義線程池

到此這篇關于一文詳解Caffeine緩存庫的常用功能與使用指南的文章就介紹到這了,更多相關Caffeine緩存庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 了解Java多線程的可見性與有序性

    了解Java多線程的可見性與有序性

    這篇文章主要介紹了了解Java多線程的可見性與有序性,在Java內(nèi)存模型中,允許編譯器和處理器對指令進行重排序,但是重排序過程不會影響到單線程程序的執(zhí)行,卻會影響到多線程并發(fā)執(zhí)行的正確性。,需要的朋友可以參考下
    2019-06-06
  • 詳解Java的內(nèi)存模型

    詳解Java的內(nèi)存模型

    本文更準確的說法應該是JVM的內(nèi)存模型,但是這里又牽扯了一些其他的前置知識,主要是想從Java入手,從源頭上梳理一遍整個Java底層運行的機制,中間會額外補充一些和題目無關的前置基礎,導致主講內(nèi)存模型的篇幅所占的比例就不是那么絕對。
    2021-06-06
  • java判斷對象中某個屬性是否為空方法代碼

    java判斷對象中某個屬性是否為空方法代碼

    這篇文章主要給大家介紹了關于java判斷對象中某個屬性是否為空的相關資料,最近遇到后臺接收值的時候,需要對接收對象進行非空校驗,需要的朋友可以參考下
    2023-07-07
  • 基于spring boot實現(xiàn)一個全局異常處理器

    基于spring boot實現(xiàn)一個全局異常處理器

    在項目開發(fā)中,我們可以基于spring boot提供的切面特性,來很輕松的實現(xiàn)全局異常的處理,所以本文主要為大家介紹了如何基于spring boot實現(xiàn)一個全局異常處理器,有需要的可以參考下
    2023-09-09
  • JavaScript裝飾器從基礎到實戰(zhàn)教程

    JavaScript裝飾器從基礎到實戰(zhàn)教程

    裝飾器是js中一種聲明式語法特性,用于在不修改原始代碼的情況下,動態(tài)擴展類、方法、屬性或參數(shù)的行為,本文將從基礎概念入手,逐步講解裝飾器的類型、用法、進階技巧及實戰(zhàn)場景,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • 詳解springboot整合ueditor踩過的坑

    詳解springboot整合ueditor踩過的坑

    這篇文章主要介紹了詳解springboot整合ueditor踩過的坑,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-06-06
  • Java Lambda表達式的方法引用和構(gòu)造器引用實例分析

    Java Lambda表達式的方法引用和構(gòu)造器引用實例分析

    這篇文章主要介紹了Java Lambda表達式的方法引用和構(gòu)造器引用,結(jié)合實例形式分析了Lambda表達式的方法引用和構(gòu)造器引用相關原理、用法及操作注意事項,需要的朋友可以參考下
    2019-09-09
  • Mybatis-Plus 條件構(gòu)造器 QueryWrapper 的基本用法

    Mybatis-Plus 條件構(gòu)造器 QueryWrapper 的基本用法

    這篇文章主要介紹了Mybatis-Plus - 條件構(gòu)造器 QueryWrapper 的使用,通過實例代碼給大家介紹了查詢示例代碼及實現(xiàn)需求,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • 劍指Offer之Java算法習題精講鏈表專題篇

    劍指Offer之Java算法習題精講鏈表專題篇

    跟著思路走,之后從簡單題入手,反復去看,做過之后可能會忘記,之后再做一次,記不住就反復做,反復尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • Java Hashtable機制深入了解

    Java Hashtable機制深入了解

    HashTable是jdk 1.0中引入的產(chǎn)物,基本上現(xiàn)在很少使用了,但是會在面試中經(jīng)常被問到。本文就來帶大家一起深入了解一下Hashtable,需要的可以參考一下
    2022-09-09

最新評論

德兴市| 中江县| 衡山县| 吐鲁番市| 来凤县| 巴青县| 福泉市| 盐城市| 大港区| 金塔县| 鄢陵县| 新竹市| 九江市| 黄大仙区| 永善县| 仁化县| 玛纳斯县| 靖西县| 育儿| 屯门区| 长汀县| 休宁县| 五莲县| 南溪县| 红原县| 长寿区| 荣成市| 湖口县| 瑞丽市| 马龙县| 喀喇沁旗| 哈巴河县| 扶沟县| 聂拉木县| 大关县| 东光县| 河津市| 马山县| 胶南市| 双峰县| 洛浦县|