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

Java實(shí)現(xiàn)本地緩存的四種方法實(shí)現(xiàn)與對(duì)比

 更新時(shí)間:2025年08月15日 08:49:47   作者:橘子編程  
本地緩存的優(yōu)點(diǎn)就是速度非???沒(méi)有網(wǎng)絡(luò)消耗,本地緩存比如 caffine,guava cache 這些都是比較常用的,下面我們來(lái)看看這四種緩存的具體實(shí)現(xiàn)吧

本地緩存比如 caffine,guava cache 這些都是比較常用的,本地緩存的優(yōu)點(diǎn)就是速度非常快,沒(méi)有網(wǎng)絡(luò)消耗,缺點(diǎn)就是應(yīng)用重啟后,緩存就會(huì)丟失。

Java緩存技術(shù)可分為遠(yuǎn)端緩存和本地緩存,遠(yuǎn)端緩存常用的方案有著名的redis,而本地緩存的代表技術(shù)主要有HashMap,Guava Cache,Caffeine和Encahche。

1、HashMap

通過(guò)Map的底層方式,直接將需要緩存的對(duì)象放在內(nèi)存中。

  • 優(yōu)點(diǎn):簡(jiǎn)單粗暴,不需要引入第三方包,比較適合一些比較簡(jiǎn)單的場(chǎng)景。
  • 缺點(diǎn):沒(méi)有緩存淘汰策略,定制化開(kāi)發(fā)成本高。
package com.taiyuan.javademoone.cachedemo;
 
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
 
/**
 * 定義一個(gè)基于LinkedHashMap實(shí)現(xiàn)的線程安全的LRU緩存類
 */
public class LRUCache extends LinkedHashMap<Object, Object> {  // 明確泛型類型為<Object, Object>,提高代碼可讀性
    /**
     * 可重入讀寫(xiě)鎖,用于保證多線程環(huán)境下對(duì)緩存的并發(fā)讀寫(xiě)操作的安全性
     */
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Lock readLock = readWriteLock.readLock();   // 讀鎖,用于并發(fā)讀取時(shí)共享訪問(wèn)
    private Lock writeLock = readWriteLock.writeLock(); // 寫(xiě)鎖,用于寫(xiě)入或修改時(shí)獨(dú)占訪問(wèn)
 
    /**
     * 緩存的最大容量限制,超過(guò)此容量將移除最久未使用的條目
     */
    private int maxSize;
 
    /**
     * 構(gòu)造函數(shù),初始化LRU緩存并設(shè)置最大容量
     *
     * @param maxSize 緩存允許存儲(chǔ)的最大條目數(shù)
     */
    public LRUCache(int maxSize) {
        // 調(diào)用父類LinkedHashMap的構(gòu)造方法:
        // 參數(shù)1:初始容量為maxSize + 1,避免頻繁擴(kuò)容
        // 參數(shù)2:負(fù)載因子為1.0f,表示哈希表填滿到100%時(shí)才擴(kuò)容
        // 參數(shù)3:accessOrder為true,表示按照訪問(wèn)順序排序,實(shí)現(xiàn)LRU策略
        super(maxSize + 1, 1.0f, true);
        this.maxSize = maxSize;
    }
 
    /**
     * 重寫(xiě)get方法,獲取指定key對(duì)應(yīng)的value,使用讀鎖保證線程安全
     *
     * @param key 要查找的鍵
     * @return 對(duì)應(yīng)的值,如果不存在則返回null
     */
    @Override
    public Object get(Object key) {
        readLock.lock();      // 加讀鎖,允許多個(gè)線程同時(shí)讀
        try {
            return super.get(key); // 調(diào)用父類的get方法
        } finally {
            readLock.unlock(); // 確保讀鎖最終被釋放
        }
    }
 
    /**
     * 重寫(xiě)put方法,向緩存中添加或更新鍵值對(duì),使用寫(xiě)鎖保證線程安全
     *
     * @param key   要插入或更新的鍵
     * @param value 要插入或更新的值
     * @return 之前與key關(guān)聯(lián)的值,如果沒(méi)有則返回null
     */
    @Override
    public Object put(Object key, Object value) {
        writeLock.lock();     // 加寫(xiě)鎖,確保同一時(shí)間只有一個(gè)線程可以寫(xiě)
        try {
            return super.put(key, value); // 調(diào)用父類的put方法
        } finally {
            writeLock.unlock(); // 確保寫(xiě)鎖最終被釋放
        }
    }
 
    /**
     * 重寫(xiě)removeEldestEntry方法,當(dāng)緩存大小超過(guò)maxSize時(shí),移除最久未使用的條目
     *
     * @param eldest 最久未訪問(wèn)的鍵值對(duì)Entry
     * @return 如果當(dāng)前緩存大小超過(guò)最大容量,則返回true,觸發(fā)刪除最老的條目;否則返回false
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return this.size() > maxSize; // 判斷當(dāng)前緩存大小是否超出限制
    }
 
 
 
    // 測(cè)試主方法
    public static void main(String[] args) {
        LRUCache cache = new LRUCache(3);
        cache.put("1", "one");
        cache.put("2", "two");
        cache.put("3", "three");
        System.out.println(cache); // 輸出:{1=one, 2=two, 3=three}
    }
}

2、Guava Cache

Guava Cache 是 Google Guava 庫(kù)中的一個(gè)本地緩存實(shí)現(xiàn),它提供了以下主要特性:

  • 自動(dòng)加載:當(dāng)緩存未命中時(shí)自動(dòng)從指定來(lái)源加載數(shù)據(jù)
  • 多種淘汰策略:支持基于大小、時(shí)間和引用的淘汰
  • 統(tǒng)計(jì)功能:內(nèi)置緩存命中率統(tǒng)計(jì)
  • 線程安全:內(nèi)置并發(fā)控制機(jī)制
  • 監(jiān)聽(tīng)器:支持緩存移除通知
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>33.4.8-jre</version>
</dependency>
package com.helloworld.demo;
 
import com.google.common.cache.*;
 
import java.util.concurrent.TimeUnit;
 
public class GuavaCacheExample {
    public static void main(String[] args) {
        // 創(chuàng)建一個(gè)Guava的LoadingCache實(shí)例,支持自動(dòng)加載緩存項(xiàng)
        LoadingCache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(100)                     // 設(shè)置緩存最大容量為100個(gè)條目
                .expireAfterWrite(10, TimeUnit.MINUTES) // 設(shè)置緩存項(xiàng)在寫(xiě)入10分鐘后自動(dòng)過(guò)期
                .recordStats()                         // 開(kāi)啟緩存統(tǒng)計(jì)功能,可以獲取命中率等信息
                .build(new CacheLoader<String, String>() { // 定義緩存未命中時(shí)的加載邏輯
                    @Override
                    public String load(String key) throws Exception {
                        // 當(dāng)根據(jù)key獲取不到緩存值時(shí),調(diào)用此方法從數(shù)據(jù)源(如數(shù)據(jù)庫(kù))加載數(shù)據(jù)
                        return fetchDataFromDatabase(key);
                    }
                });
 
        try {
            // 第一次獲取key為"user:1001"的值,由于緩存中沒(méi)有,會(huì)觸發(fā)load方法從數(shù)據(jù)庫(kù)加載
            System.out.println("第一次獲取(從數(shù)據(jù)庫(kù)加載): " + cache.get("user:1001"));
            // 第二次獲取相同的key,此時(shí)緩存中已有該值,直接從緩存返回,不會(huì)再次加載
            System.out.println("第二次獲取(從緩存獲取): " + cache.get("user:1001"));
 
            // 手動(dòng)向緩存中放入一個(gè)鍵值對(duì),繞過(guò)自動(dòng)加載邏輯
            cache.put("user:1002", "Manual Data");
            // 獲取手動(dòng)放入的緩存值
            System.out.println("手動(dòng)放入的數(shù)據(jù): " + cache.get("user:1002"));
 
            // 打印緩存的統(tǒng)計(jì)信息,如命中率、加載次數(shù)等
            System.out.println("\n緩存統(tǒng)計(jì):");
            System.out.println(cache.stats());
 
            // 手動(dòng)移除指定key的緩存項(xiàng)
            cache.invalidate("user:1001");
            // 嘗試獲取已被移除的緩存項(xiàng),返回null表示不存在
            System.out.println("\n移除后獲取: " + cache.getIfPresent("user:1001"));
 
        } catch (Exception e) {
            e.printStackTrace(); // 捕獲并打印異常信息
        }
    }
 
    // 模擬從數(shù)據(jù)庫(kù)中根據(jù)key獲取數(shù)據(jù)的邏輯
    private static String fetchDataFromDatabase(String key) {
        // 打印當(dāng)前正在加載的key,用于觀察加載行為
        System.out.println("正在從數(shù)據(jù)庫(kù)加載數(shù)據(jù): " + key);
        try {
            Thread.sleep(500); // 模擬數(shù)據(jù)庫(kù)查詢的延遲,增加真實(shí)感
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
        }
        // 返回模擬的數(shù)據(jù)庫(kù)查詢結(jié)果
        return "Data for " + key;
    }
}

3、Caffeine

Caffeine采用了W-TinyLFU(LUR和LFU的優(yōu)點(diǎn)結(jié)合)開(kāi)源的緩存技術(shù)。緩存性能接近理論最優(yōu),屬于是Guava Cache的增強(qiáng)版。

Caffeine 是一個(gè)高性能的 Java 緩存庫(kù),它改進(jìn)了 Guava Cache 的設(shè)計(jì),具有以下特點(diǎn):

  • 優(yōu)化的淘汰算法:采用 W-TinyLFU 算法,結(jié)合了 LRU 和 LFU 的優(yōu)點(diǎn)
  • 卓越的性能:讀寫(xiě)性能接近理論最優(yōu)值
  • 異步支持:提供異步加載和刷新機(jī)制
  • 豐富的特性:支持多種淘汰策略、權(quán)重計(jì)算、統(tǒng)計(jì)等功能
  • 內(nèi)存友好:相比 Guava Cache 減少約 50% 的內(nèi)存占用
<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
  <version>2.9.3</version>
</dependency>
package com.helloworld.demo;
 
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
 
import java.util.concurrent.TimeUnit;
 
public class CaffeineCacheTest {
    public static void main(String[] args) throws Exception {
        // 創(chuàng)建一個(gè) Caffeine 緩存實(shí)例(注意:原注釋寫(xiě)的是 Guava Cache,實(shí)際使用的是 Caffeine)
        Cache<String, String> loadingCache = Caffeine.newBuilder()
                .initialCapacity(5) // 設(shè)置初始緩存容量為 5 個(gè)條目
                .maximumSize(10)    // 設(shè)置緩存最大容量為 10 個(gè)條目,超過(guò)時(shí)將按照策略淘汰
                .expireAfterWrite(17, TimeUnit.SECONDS) // 寫(xiě)入后 17 秒過(guò)期
                .expireAfterAccess(17, TimeUnit.SECONDS) // 最后一次訪問(wèn)后 17 秒過(guò)期
                .build(); // 構(gòu)建緩存實(shí)例
 
        String key = "key"; // 定義緩存的鍵
        loadingCache.put(key, "這是測(cè)試方法"); // 手動(dòng)將鍵值對(duì)放入緩存
        // 從緩存中獲取指定鍵的值
        String value = loadingCache.getIfPresent(key);
        System.out.println(" 從緩存中獲取指定鍵(key)的值:" + value); // 輸出:這是測(cè)試方法
 
        // 將指定的鍵從緩存中移除(使其失效)
        loadingCache.invalidate(key);
        value = loadingCache.getIfPresent(key);
        System.out.println(" 從緩存中獲取指定鍵(key)的值:" + value); // 輸出:null
    }
 
}

4、Encache

Ehcache是一個(gè)純java的進(jìn)程內(nèi)緩存框架,具有快速、精干的特點(diǎn)。是hibernate默認(rèn)的cacheprovider。

  • 優(yōu)點(diǎn):支持多種緩存淘汰算法,包括LFU,LRU和FIFO;緩存支持堆內(nèi)緩存,堆外緩存和磁盤(pán)緩存;支持多種集群方案,解決數(shù)據(jù)共享問(wèn)題。
  • 缺點(diǎn):性能比Caffeine差
<dependency>
  <groupId>org.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>3.10.8</version>
</dependency>
package com.helloworld.demo;
 
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
 
/**
 * Ehcache 基礎(chǔ)使用示例類
 */
public class EhcacheBasicExample {
    public static void main(String[] args) {
        // 1. 創(chuàng)建緩存管理器(CacheManager),它是管理所有緩存的核心對(duì)象
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
        // 初始化緩存管理器,使其可以開(kāi)始工作
        cacheManager.init();
 
        // 2. 創(chuàng)建一個(gè)緩存配置,定義緩存的鍵值類型和存儲(chǔ)策略
        CacheConfigurationBuilder<String, String> config = CacheConfigurationBuilder
        .newCacheConfigurationBuilder(
            String.class,         // 緩存鍵的類型為 String
            String.class,         // 緩存值的類型為 String
            ResourcePoolsBuilder.heap(100) // 配置堆內(nèi)內(nèi)存緩存最多存儲(chǔ) 100 個(gè)條目
        );
 
        // 3. 根據(jù)配置創(chuàng)建一個(gè)名為 "myCache" 的緩存實(shí)例
        Cache<String, String> myCache = cacheManager.createCache("myCache", config);
 
        // 4. 使用緩存:存儲(chǔ)和讀取數(shù)據(jù)
        myCache.put("key1", "value1");          // 往緩存中放入一個(gè)鍵值對(duì)
        String value = myCache.get("key1");     // 從緩存中根據(jù) key 獲取對(duì)應(yīng)的 value
        System.out.println("獲取的值: " + value); // 打印獲取到的緩存值
 
        // 5. 使用完緩存后,關(guān)閉緩存管理器以釋放資源
        cacheManager.close();
    }
}

到此這篇關(guān)于Java實(shí)現(xiàn)本地緩存的四種方法實(shí)現(xiàn)與對(duì)比的文章就介紹到這了,更多相關(guān)Java本地緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 利用Java實(shí)現(xiàn)文件鎖定功能

    利用Java實(shí)現(xiàn)文件鎖定功能

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)文件鎖定功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-08-08
  • Springboot集成Sentinel?組件實(shí)現(xiàn)基本限流功能(快速入門(mén))

    Springboot集成Sentinel?組件實(shí)現(xiàn)基本限流功能(快速入門(mén))

    Sentinel是阿里巴巴開(kāi)發(fā)的面向云原生微服務(wù)的高可用流控防護(hù)組件,支持流量控制、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多維度防護(hù),適用于秒殺、消息削峰填谷等場(chǎng)景,本文給大家介紹Springboot集成Sentinel組件實(shí)現(xiàn)基本限流功能,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • 如何在Spring boot加入shiro支持

    如何在Spring boot加入shiro支持

    這篇文章主要介紹了如何在Spring boot加入shiro支持,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Java如何根據(jù)根據(jù)IP地址獲取省市

    Java如何根據(jù)根據(jù)IP地址獲取省市

    這篇文章主要為大家詳細(xì)介紹了兩種在Java中獲取IP地址對(duì)應(yīng)地理位置信息的方法,分別是使用ip2region庫(kù)和GeoIP庫(kù),感興趣的小伙伴可以了解下
    2025-01-01
  • Java 信號(hào)量Semaphore的實(shí)現(xiàn)

    Java 信號(hào)量Semaphore的實(shí)現(xiàn)

    這篇文章主要介紹了Java 信號(hào)量Semaphore的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • SpringBoot?@GroupSequenceProvider注解實(shí)現(xiàn)bean多屬性聯(lián)合校驗(yàn)的示例代碼

    SpringBoot?@GroupSequenceProvider注解實(shí)現(xiàn)bean多屬性聯(lián)合校驗(yàn)的示例代碼

    這篇文章主要介紹了SpringBoot?@GroupSequenceProvider注解實(shí)現(xiàn)bean多屬性聯(lián)合校驗(yàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • 一文詳解Mybatis-plus的介紹與使用

    一文詳解Mybatis-plus的介紹與使用

    Mybatis-Plus?是?MyBatis?的一個(gè)增強(qiáng)工具,專門(mén)針對(duì)于傳統(tǒng)MyBatis開(kāi)發(fā)中sql需要手動(dòng)進(jìn)行映射配置繁瑣缺點(diǎn)的一款框架技術(shù)。本文將為大家詳細(xì)講講Mybatis-plus的介紹與使用,感興趣的可以了解一下
    2022-07-07
  • Spring Boot開(kāi)發(fā)編譯后讀取不到@spring.profiles.active@的問(wèn)題及解決步驟

    Spring Boot開(kāi)發(fā)編譯后讀取不到@spring.profiles.active@的問(wèn)題及解決步驟

    這篇文章主要介紹了Spring Boot開(kāi)發(fā)編譯后讀取不到@spring.profiles.active@的問(wèn)題及解決步驟,需要的朋友可以參考下
    2024-12-12
  • JAVA 實(shí)現(xiàn)延遲隊(duì)列的方法

    JAVA 實(shí)現(xiàn)延遲隊(duì)列的方法

    這篇文章主要介紹了JAVA 實(shí)現(xiàn)延遲隊(duì)列的方法,文中講解非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • 詳解Struts2動(dòng)態(tài)方法調(diào)用

    詳解Struts2動(dòng)態(tài)方法調(diào)用

    這篇文章主要介紹了詳解Struts2動(dòng)態(tài)方法調(diào)用,涉及調(diào)用方法的代碼,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-09-09

最新評(píng)論

涪陵区| 康马县| 蚌埠市| 北海市| 中山市| 巫山县| 剑河县| 日土县| 武隆县| 蚌埠市| 呼玛县| 政和县| 广宗县| 临汾市| 金川县| 盐津县| 松滋市| 漳平市| 石河子市| 马关县| 东乡县| 新余市| 温泉县| 溆浦县| 承德县| 永城市| 清徐县| 淮滨县| 桃园县| 巢湖市| 贵定县| 香港| 潮安县| 房产| 淮滨县| 贵南县| 宜章县| 乐东| 盘锦市| 衡阳市| 峨眉山市|