欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

本地緩存在Java中的實現(xiàn)過程

 更新時間:2025年06月30日 08:40:40   作者:找不到、了  
這篇文章主要介紹了本地緩存在Java中的實現(xiàn)過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

本地緩存是Java應(yīng)用中常用的性能優(yōu)化手段。如下圖所示:

在分布式系統(tǒng)中,同一個應(yīng)用部署有多個,這些應(yīng)用的本地緩存僅限于本地應(yīng)用內(nèi)部,是互不相通的,在負(fù)載均衡中,分配到處理的各個應(yīng)用讀取本地緩存的結(jié)果可能會存在不一致。

注意:本地緩存是jvm層面的緩存,一旦該應(yīng)用重啟或停止了,緩存也消失了。

1、介紹

引入緩存,主要用于實現(xiàn)系統(tǒng)的高性能,高并發(fā)。如下圖所示:

將數(shù)據(jù)庫查詢出來的數(shù)據(jù)放入緩存服務(wù)中,因為緩存是存儲在內(nèi)存中的,內(nèi)存的讀寫性能遠(yuǎn)超磁盤的讀寫性能,所以訪問的速度非常快。

注意:

但是電腦重啟后,內(nèi)存中的數(shù)據(jù)會全部清除,而磁盤中的數(shù)據(jù)雖然讀寫性能很差,但是數(shù)據(jù)不會丟失。

2、實現(xiàn)方式

2.1、HashMap

最簡單的方式是使用ConcurrentHashMap實現(xiàn)線程安全的緩存。

代碼示例如下:

import java.util.concurrent.ConcurrentHashMap;

public class SimpleCache<K, V> {
    private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
    
    public void put(K key, V value) {
        cache.put(key, value);
    }
    
    public V get(K key) {
        return cache.get(key);
    }
    
    public void remove(K key) {
        cache.remove(key);
    }
    
    public void clear() {
        cache.clear();
    }
}

適用場景

  • 簡單的內(nèi)存緩存需求
  • 緩存數(shù)據(jù)量很?。◣装贄l以內(nèi))
  • 不需要過期策略或淘汰機(jī)制
  • 快速原型開發(fā)

優(yōu)點

  • 零依賴
  • 實現(xiàn)簡單直接
  • 性能極高

缺點

  • 缺乏過期、淘汰等高級功能
  • 需要手動實現(xiàn)線程安全(使用ConcurrentHashMap除外)

如下所示:

// 簡單的配置項緩存
private static final Map<String, String> CONFIG_CACHE = new ConcurrentHashMap<>();

public String getConfig(String key) {
    return CONFIG_CACHE.computeIfAbsent(key, k -> loadConfigFromDB(k));
}

2.2、LinkedHashMap

利用LinkedHashMap的訪問順序特性實現(xiàn)LRU(最近最少使用)緩存。

如下圖所示:

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int maxSize;
    
    public LRUCache(int maxSize) {
        super(maxSize, 0.75f, true);
        this.maxSize = maxSize;
    }
    
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > maxSize;
    }
}

適用場景

  • 需要簡單的LRU淘汰策略
  • 緩存數(shù)量固定且不大
  • 不想引入第三方庫

優(yōu)點

  • JDK內(nèi)置,無額外依賴
  • 實現(xiàn)LRU策略簡單

缺點

  • 功能有限
  • 并發(fā)性能一般

如下所示:

// 最近訪問的用戶基本信息緩存
private static final int MAX_ENTRIES = 1000;
private static final Map<Long, UserInfo> USER_CACHE = 
    Collections.synchronizedMap(new LinkedHashMap<Long, UserInfo>(MAX_ENTRIES, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > MAX_ENTRIES;
        }
    });

2.3、Guava Cache

Guava Cache是JVM層面的緩存,服務(wù)停掉或重啟便消失了,在分布式環(huán)境中也有其局限性。

因此,比較好的緩存方案是Guava Cache+Redis雙管齊下。先查詢Guava Cache,命中即返回,未命中再查redis。

引入依賴:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.2-jre</version> <!-- 使用最新版本 -->
</dependency>

代碼如下所示:

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

public class GuavaCacheExample {
    public static void main(String[] args) {
       //建造者模式
        Cache<String, String> cache = CacheBuilder.newBuilder()
            .maximumSize(100) // 最大緩存數(shù)量
            .expireAfterWrite(10, TimeUnit.MINUTES) // 寫入后10分鐘過期
            .build();
        
        // 放入緩存
        cache.put("key1", "value1");
        
        // 獲取緩存
        String value = cache.getIfPresent("key1");
        System.out.println(value);
        
        // 移除緩存
        cache.invalidate("key1");
    }
}

適用場景

  • 需要豐富的緩存特性(過期、淘汰、刷新等)
  • 中等規(guī)模緩存(幾千到幾十萬條目)
  • 需要良好的并發(fā)性能
  • 項目已經(jīng)使用Guava庫

優(yōu)點

  • 功能全面(權(quán)重、刷新、統(tǒng)計等)
  • 良好的API設(shè)計
  • 中等規(guī)模的優(yōu)秀性能

缺點

  • 不如Caffeine性能高
  • 大型緩存時內(nèi)存效率一般

示例如下:

// 商品詳情緩存,30分鐘自動過期,最大10000條
LoadingCache<Long, Product> productCache = CacheBuilder.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(30, TimeUnit.MINUTES)
    .recordStats()
    .build(new CacheLoader<Long, Product>() {
        @Override
        public Product load(Long id) {
            return productDao.findById(id);
        }
    });

// 使用
Product product = productCache.get(123L);

2.4、Caffeine Cache

Caffeine是Guava Cache的現(xiàn)代替代品,性能更好。

引入依賴:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version> <!-- 使用最新版本 -->
</dependency>

代碼示例如下:

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

public class CaffeineCacheExample {
    public static void main(String[] args) {
        Cache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(10_000)
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .build();
        
        cache.put("key1", "value1");
        String value = cache.getIfPresent("key1");
        System.out.println(value);
    }
}

適用場景

  • 高性能要求的應(yīng)用
  • 大規(guī)模緩存(幾十萬以上條目)
  • 需要最優(yōu)的讀寫性能
  • 現(xiàn)代Java項目(JDK8+)

優(yōu)點

  • 目前性能最好的Java緩存庫
  • 內(nèi)存效率高
  • 豐富的特性(異步加載、權(quán)重等)
  • 優(yōu)秀的并發(fā)性能

缺點

  • 較新的庫,老項目可能不適用
  • API與Guava不完全兼容

示例如下:

// 高性能的秒殺商品庫存緩存
Cache<Long, AtomicInteger> stockCache = Caffeine.newBuilder()
    .maximumSize(100_000)
    .expireAfterWrite(10, TimeUnit.SECONDS) // 庫存信息短期有效
    .refreshAfterWrite(1, TimeUnit.SECONDS) // 1秒后訪問自動刷新
    .build(id -> new AtomicInteger(queryStockFromDB(id)));

// 使用
int remaining = stockCache.get(productId).decrementAndGet();

2.5、Ehcache

Ehcache是一個成熟的Java緩存框架:功能更強(qiáng)大,支持磁盤持久化、分布式緩存等。

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.10.8</version>
</dependency>
import org.ehcache.Cache;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.core.config.DefaultConfiguration;
import org.ehcache.core.spi.service.LocalPersistenceService;
import org.ehcache.impl.config.persistence.DefaultPersistenceConfiguration;
import org.ehcache.impl.persistence.DefaultLocalPersistenceService;

public class EhcacheExample {
    public static void main(String[] args) {
        // 配置持久化到磁盤
        LocalPersistenceService persistenceService = new DefaultLocalPersistenceService(
            new DefaultPersistenceConfiguration(new File("cache-data")));

        // 創(chuàng)建緩存管理器
        DefaultConfiguration config = new DefaultConfiguration(
            persistenceService, ResourcePoolsBuilder.heap(100).build());

        Cache<String, String> cache = CacheConfigurationBuilder.newCacheConfigurationBuilder(
                String.class, String.class,
                ResourcePoolsBuilder.newResourcePoolsBuilder()
                    .heap(100, MemoryUnit.MB)    // 堆內(nèi)內(nèi)存
                    .disk(1, MemoryUnit.GB)     // 磁盤持久化
            ).buildConfig(String.class);

        // 寫入數(shù)據(jù)
        cache.put("key1", "value1");

        // 讀取數(shù)據(jù)
        String value = cache.get("key1");
        System.out.println("Value: " + value); // 輸出 Value: value1

        // 關(guān)閉資源
        persistenceService.close();
    }
}

適用場景

  • 企業(yè)級應(yīng)用
  • 需要持久化到磁盤
  • 需要分布式緩存支持
  • 復(fù)雜的緩存拓?fù)湫枨?/li>

優(yōu)點

  • 功能最全面(堆外、磁盤、集群等)
  • 成熟的監(jiān)控和管理
  • 良好的Spring集成

缺點

  • 性能不如Caffeine
  • 配置較復(fù)雜
  • 內(nèi)存效率一般

示例如下:

<!-- ehcache.xml -->
<cache name="financialDataCache"
       maxEntriesLocalHeap="10000"
       timeToLiveSeconds="3600"
       memoryStoreEvictionPolicy="LFU">
    <persistence strategy="localTempSwap"/>
</cache>
// 金融數(shù)據(jù)緩存,需要持久化
@Cacheable(value = "financialDataCache", 
           key = "#symbol + '_' + #date.format(yyyyMMdd)")
public FinancialData getFinancialData(String symbol, LocalDate date) {
    // 從外部API獲取數(shù)據(jù)
}

2.6、使用Spring Cache注解

Spring框架提供了緩存抽象。關(guān)于cache的常用注解如下:

1、引入依賴

<dependencies>
    <!-- Spring Boot Starter Cache -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    
    <!-- 使用Caffeine作為緩存實現(xiàn) -->
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
    </dependency>
</dependencies>

2、使用緩存配置類

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.caffeine.CaffeineCacheManager;

import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CaffeineCacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(500)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .recordStats());
        return cacheManager;
    }


    @Bean
    @Primary
    public CacheManager productCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("products");
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(1, TimeUnit.HOURS));
        return cacheManager;
    }
    
    @Bean
    public CacheManager userCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("users");
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(500)
                .expireAfterAccess(30, TimeUnit.MINUTES));
        return cacheManager;
    }
}

注意:在設(shè)置緩存配置類的時候,可以配置多個。

然后在服務(wù)類中指定使用哪個緩存管理器:

@Service
public class UserService {
    
    @Cacheable(value = "users", cacheManager = "userCacheManager")
    public User getUserById(Long id) {
        // ...
    }
}

3、服務(wù)類使用緩存

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class ProductService {
    
    // 根據(jù)ID獲取產(chǎn)品,如果緩存中有則直接返回
    @Cacheable(value = "products", key = "#id")
    public Product getProductById(Long id) {
        // 模擬數(shù)據(jù)庫查詢
        System.out.println("查詢數(shù)據(jù)庫獲取產(chǎn)品: " + id);
        return findProductInDB(id);
    }
    
    // 更新產(chǎn)品信息,并更新緩存
    @CachePut(value = "products", key = "#product.id")
    public Product updateProduct(Product product) {
        // 模擬數(shù)據(jù)庫更新
        System.out.println("更新數(shù)據(jù)庫中的產(chǎn)品: " + product.getId());
        return updateProductInDB(product);
    }
    
    // 刪除產(chǎn)品,并清除緩存
    @CacheEvict(value = "products", key = "#id")
    public void deleteProduct(Long id) {
        // 模擬數(shù)據(jù)庫刪除
        System.out.println("從數(shù)據(jù)庫刪除產(chǎn)品: " + id);
    }
    
    // 清除所有產(chǎn)品緩存
    @CacheEvict(value = "products", allEntries = true)
    public void clearAllCache() {
        System.out.println("清除所有產(chǎn)品緩存");
    }
    
    // 模擬數(shù)據(jù)庫查詢方法
    private Product findProductInDB(Long id) {
        // 實際項目中這里應(yīng)該是數(shù)據(jù)庫操作
        return new Product(id, "產(chǎn)品" + id, 100.0);
    }
    
    // 模擬數(shù)據(jù)庫更新方法
    private Product updateProductInDB(Product product) {
        // 實際項目中這里應(yīng)該是數(shù)據(jù)庫操作
        return product;
    }
}

4、實體類

public class Product {
    private Long id;
    private String name;
    private double price;
    
    // 構(gòu)造方法、getter和setter省略
    // 實際項目中應(yīng)該包含這些方法
}

5、控制器示例:

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/products")
public class ProductController {
    
    private final ProductService productService;
    
    public ProductController(ProductService productService) {
        this.productService = productService;
    }
    
    @GetMapping("/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productService.getProductById(id);
    }
    
    @PutMapping
    public Product updateProduct(@RequestBody Product product) {
        return productService.updateProduct(product);
    }
    
    @DeleteMapping("/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
    }
    
    @PostMapping("/clear-cache")
    public void clearCache() {
        productService.clearAllCache();
    }
}

適用場景

  • Spring/Spring Boot項目
  • 需要聲明式緩存
  • 可能切換緩存實現(xiàn)
  • 需要與Spring生態(tài)深度集成

優(yōu)點

  • 統(tǒng)一的緩存抽象
  • 注解驅(qū)動,使用簡單
  • 輕松切換實現(xiàn)(Caffeine/Ehcache/Redis等)

缺點

  • 性能取決于底層實現(xiàn)
  • 高級功能需要了解底層實現(xiàn)

如下所示:

// 多級緩存配置:本地緩存+Redis
@Configuration
@EnableCaching
public class CacheConfig {
    
    // 本地一級緩存
    @Bean
    @Primary
    public CacheManager localCacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(30, TimeUnit.MINUTES));
        return manager;
    }
    
    // Redis二級緩存
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
                .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
                        .entryTtl(Duration.ofHours(2))
                        .disableCachingNullValues())
                .build();
    }
}

// 服務(wù)層使用
@Service
public class ProductService {
    
    @Cacheable(cacheNames = "products", 
               cacheManager = "localCacheManager") // 先用本地緩存
    @Cacheable(cacheNames = "products", 
               cacheManager = "redisCacheManager", 
               unless = "#result == null") // 再用Redis緩存
    public Product getProduct(Long id) {
        return productRepository.findById(id);
    }
}

3、性能對比

1.合理設(shè)置緩存大小

根據(jù)可用內(nèi)存設(shè)置上限。使用weigher對大型對象特殊處理。

2.選擇合適的過期策略

// 根據(jù)業(yè)務(wù)場景選擇
.expireAfterWrite(10, TimeUnit.MINUTES)  // 寫入后固定時間過期
.expireAfterAccess(30, TimeUnit.MINUTES) // 訪問后延長有效期
.refreshAfterWrite(1, TimeUnit.MINUTES)  // 寫入后定時刷新

3.監(jiān)控緩存命中率

CacheStats stats = cache.stats();
double hitRate = stats.hitRate();      // 命中率
long evictionCount = stats.evictionCount(); // 淘汰數(shù)量

4.避免緩存污染

// 不緩存null或空值
.build(key -> {
    Value value = queryFromDB(key);
    return value == null ? Optional.empty() : value;
});

@Cacheable(unless = "#result == null || #result.isEmpty()")

5.考慮使用軟引用(內(nèi)存敏感場景):

.softValues() // 內(nèi)存不足時自動回收

根據(jù)您的具體業(yè)務(wù)需求、數(shù)據(jù)規(guī)模和性能要求,選擇最適合的緩存方案,并持續(xù)監(jiān)控和優(yōu)化緩存效果。

4、使用建議

簡單小規(guī)模緩存ConcurrentHashMapLinkedHashMap

  • 適用于配置項、簡單查詢結(jié)果緩存
  • 無外部依賴,實現(xiàn)簡單

中等規(guī)模通用緩存Guava CacheCaffeine

  • 適用于大多數(shù)業(yè)務(wù)數(shù)據(jù)緩存
  • Guava適合已有Guava依賴的項目
  • Caffeine性能更好,推薦新項目使用

高性能大規(guī)模緩存Caffeine

  • 適用于高并發(fā)、高性能要求的場景
  • 如秒殺系統(tǒng)、高頻交易系統(tǒng)

企業(yè)級復(fù)雜需求Ehcache

  • 需要持久化、集群等高級功能
  • 已有Ehcache使用經(jīng)驗的項目

Spring項目Spring Cache + Caffeine

  • 利用Spring抽象層,方便后續(xù)擴(kuò)展
  • 推薦Caffeine作為底層實現(xiàn)

多級緩存架構(gòu)Caffeine + Redis

  • 本地緩存作為一級緩存
  • Redis作為二級分布式緩存
  • 通過Spring Cache抽象統(tǒng)一管理

總結(jié)

內(nèi)存管理‌:設(shè)置合理的 maximumSize 或 expireAfterWrite,避免內(nèi)存溢出(OOM)。

并發(fā)安全‌:Guava/Caffeine/Ehcache 均為線程安全,直接使用即可。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中RabbitMQ的幾種消息確認(rèn)機(jī)制

    Java中RabbitMQ的幾種消息確認(rèn)機(jī)制

    RabbitMQ消息確認(rèn)機(jī)制指的是在消息傳遞過程中,發(fā)送方發(fā)送消息后,接收方需要對消息進(jìn)行確認(rèn),以確保消息被正確地接收和處理,本文主要介紹了Java中RabbitMQ的幾種消息確認(rèn)機(jī)制,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • Java輸入年份和月份判斷多少天實例代碼

    Java輸入年份和月份判斷多少天實例代碼

    這篇文章主要給大家介紹了關(guān)于Java輸入年度和月份判斷多少天的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java設(shè)計模式之抽象工廠模式AbstractFactoryPattern詳解

    Java設(shè)計模式之抽象工廠模式AbstractFactoryPattern詳解

    這篇文章主要介紹了Java設(shè)計模式之抽象工廠模式AbstractFactoryPattern詳解,抽象工廠模式是一種軟件開發(fā)設(shè)計模式,抽象工廠模式提供了一種方式,可以將一組具有同一主題的單獨(dú)的工廠封裝起來,需要的朋友可以參考下
    2023-10-10
  • kaptcha驗證碼使用方法詳解

    kaptcha驗證碼使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了kaptcha驗證碼的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • 使用IDEA插件反編譯jar包的實現(xiàn)方式

    使用IDEA插件反編譯jar包的實現(xiàn)方式

    這篇文章主要介紹了使用IDEA插件反編譯jar包的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • 基于SSM?集成?Freemarker模板引擎的方法

    基于SSM?集成?Freemarker模板引擎的方法

    這篇文章主要介紹了SSM?集成?Freemarker模板引擎,SSM?架構(gòu)下一般采用?Freemarker,Spring?Boot?架構(gòu)下一般推薦采用?Thymeleaf?模板引擎,需要的朋友可以參考下
    2022-01-01
  • java中ZXing 生成、解析二維碼圖片的小示例

    java中ZXing 生成、解析二維碼圖片的小示例

    ZXing 是一個開源 Java 類庫用于解析多種格式的 1D/2D 條形碼,這篇文章主要介紹了java中ZXing 生成、解析二維碼圖片的小示例 ,有興趣的可以了解一下。
    2017-01-01
  • Intellij IDEA 2020.3 配置教程詳解

    Intellij IDEA 2020.3 配置教程詳解

    這篇文章主要介紹了Intellij IDEA 2020.3 配置教程詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • idea運(yùn)行jsp文件的時候顯示404問題及解決

    idea運(yùn)行jsp文件的時候顯示404問題及解決

    這篇文章主要介紹了idea運(yùn)行jsp文件的時候顯示404問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Java實戰(zhàn)之實現(xiàn)用戶登錄

    Java實戰(zhàn)之實現(xiàn)用戶登錄

    這篇文章主要介紹了Java實戰(zhàn)之實現(xiàn)用戶登錄,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04

最新評論