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

java如何實現(xiàn)高并發(fā)場景下三級緩存的數(shù)據(jù)一致性

 更新時間:2025年07月23日 16:27:36   作者:碼出極致  
這篇文章主要為大家詳細介紹了java如何實現(xiàn)高并發(fā)場景下三級緩存的數(shù)據(jù)一致性,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

下面代碼是一個使用Java和Redisson實現(xiàn)的三級緩存服務(wù),主要功能包括:

1.緩存結(jié)構(gòu)

  • 本地緩存:使用Caffeine實現(xiàn),最大容量10,000,寫入后10分鐘過期
  • 分布式緩存:使用Redisson的RMap結(jié)構(gòu)操作Redis
  • 數(shù)據(jù)庫:作為最終數(shù)據(jù)源

2.數(shù)據(jù)讀取流程

  • 先查本地緩存,命中則返回
  • 未命中則查Redis,命中則更新本地緩存并返回
  • 仍未命中則獲取鎖,再次檢查兩級緩存(雙重檢查)
  • 最后從數(shù)據(jù)庫讀取,更新兩級緩存后返回

3.數(shù)據(jù)更新流程

  • 使用分布式鎖保證寫操作原子性
  • 先更新數(shù)據(jù)庫
  • 刪除本地緩存和Redis緩存
  • 通過Redis Pub/Sub發(fā)布緩存清除消息給集群內(nèi)其他節(jié)點
  • 執(zhí)行延遲雙刪(100毫秒后再次刪除Redis緩存)

4.并發(fā)控制

  • 讀取時使用本地鎖(ReentrantLock)防止緩存擊穿
  • 更新時使用Redisson分布式鎖(RLock)保證跨節(jié)點原子性
  • 鎖使用完成后從ConcurrentHashMap中移除

5.集群同步

  • 使用Redis的RTopic實現(xiàn)消息發(fā)布訂閱
  • 接收到清除消息時自動刪除本地緩存
  • 確保集群內(nèi)各節(jié)點緩存一致性

該實現(xiàn)綜合運用了延遲雙刪、發(fā)布訂閱、鎖機制和TTL等多種策略,保障了高并發(fā)場景下三級緩存的數(shù)據(jù)一致性,尤其適合分布式微服務(wù)架構(gòu)。

實戰(zhàn)代碼:

import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.redisson.api.*;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.CacheBuilder;

@Service
public class CacheService {
    // 本地一級緩存(Caffeine)
    private final Cache<String, Object> localCache;
    // Redisson客戶端,用于分布式操作
    private final RedissonClient redissonClient;
    // 鎖緩存,用于控制并發(fā)
    private final ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    // 延遲任務(wù)執(zhí)行器
    private final ScheduledExecutorService scheduledExecutorService;
    // 主題訂閱,用于接收集群消息
    private final RTopic cacheClearTopic;

    @Autowired
    public CacheService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
        this.localCache = CacheBuilder.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
        this.scheduledExecutorService = Executors.newScheduledThreadPool(5);
        this.cacheClearTopic = redissonClient.getTopic("cache:clear");
        
        // 注冊消息監(jiān)聽器
        cacheClearTopic.addListener(String.class, (channel, key) -> {
            localCache.invalidate(key);
        });
    }

    // 讀取緩存
    public Object get(String key) {
        // 1. 先查本地緩存
        Object value = localCache.getIfPresent(key);
        if (value != null) {
            return value;
        }

        // 2. 本地緩存未命中,查Redis
        RMap<String, Object> redisMap = redissonClient.getMap("cache");
        value = redisMap.get(key);
        if (value != null) {
            localCache.put(key, value);
            return value;
        }

        // 3. Redis未命中,查數(shù)據(jù)庫
        ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock());
        lock.lock();
        try {
            // 雙重檢查
            value = localCache.getIfPresent(key);
            if (value != null) {
                return value;
            }
            
            value = redisMap.get(key);
            if (value != null) {
                localCache.put(key, value);
                return value;
            }

            // 從數(shù)據(jù)庫讀取
            value = readFromDatabase(key);
            if (value != null) {
                // 放入Redis并設(shè)置TTL
                redisMap.put(key, value, 300, TimeUnit.SECONDS);
                // 放入本地緩存
                localCache.put(key, value);
            }
            return value;
        } finally {
            lock.unlock();
            lockMap.remove(key);
        }
    }

    // 更新數(shù)據(jù)
    public void update(String key, Object value) {
        // 使用分布式鎖保證寫操作的原子性
        RLock lock = redissonClient.getLock("writeLock:" + key);
        lock.lock();
        try {
            // 1. 更新數(shù)據(jù)庫
            boolean success = updateDatabase(key, value);
            if (success) {
                // 2. 先刪除本地緩存
                localCache.invalidate(key);
                // 3. 刪除Redis緩存
                RMap<String, Object> redisMap = redissonClient.getMap("cache");
                redisMap.remove(key);
                // 4. 發(fā)布清除緩存的消息到集群
                cacheClearTopic.publish(key);
                // 5. 延遲雙刪
                scheduledExecutorService.schedule(() -> {
                    redisMap.remove(key);
                }, 100, TimeUnit.MILLISECONDS);
            }
        } finally {
            lock.unlock();
        }
    }

    // 從數(shù)據(jù)庫讀取數(shù)據(jù)(示例方法)
    private Object readFromDatabase(String key) {
        // 實際實現(xiàn)中會查詢數(shù)據(jù)庫
        return "data_from_db_" + key;
    }

    // 更新數(shù)據(jù)庫(示例方法)
    private boolean updateDatabase(String key, Object value) {
        // 實際實現(xiàn)中會更新數(shù)據(jù)庫
        return true;
    }
}    

redisson配置

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        // 單機模式配置
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              .setConnectionMinimumIdleSize(5)
              .setConnectionPoolSize(50);
        
        // 集群模式配置示例
        /*
        config.useClusterServers()
              .addNodeAddress("redis://node1:6379", "redis://node2:6379")
              .setScanInterval(2000)
              .setMasterConnectionMinimumIdleSize(10)
              .setMasterConnectionPoolSize(64)
              .setSlaveConnectionMinimumIdleSize(10)
              .setSlaveConnectionPoolSize(64);
        */
        
        return Redisson.create(config);
    }
}    

到此這篇關(guān)于java如何實現(xiàn)高并發(fā)場景下三級緩存的數(shù)據(jù)一致性的文章就介紹到這了,更多相關(guān)java三級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring之借助Redis設(shè)計一個簡單訪問計數(shù)器的示例

    Spring之借助Redis設(shè)計一個簡單訪問計數(shù)器的示例

    本篇文章主要介紹了Spring之借助Redis設(shè)計一個簡單訪問計數(shù)器的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • RestTemplate未使用線程池問題的解決方法

    RestTemplate未使用線程池問題的解決方法

    今天給大家?guī)淼氖顷P(guān)于Springboot的相關(guān)知識,文章圍繞著RestTemplate未使用線程池展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java關(guān)鍵字volatile詳析

    Java關(guān)鍵字volatile詳析

    這篇文章主要介紹了Java關(guān)鍵字volatile,volatile關(guān)鍵字可以說是Java虛擬機提供的最輕量級的同步機制,但對于為什么它只能保證可見性,不保證原子性,它又是如何禁用指令重排的,還有很多同學沒徹底理解,文章會讓大家牢掌握一個Java核心知識點
    2022-01-01
  • java事件處理模型知識點總結(jié)

    java事件處理模型知識點總結(jié)

    在本篇文章里小辮給大家分享的是一篇關(guān)于java事件處理模型知識點總結(jié)內(nèi)容,有興趣的朋友們可以學習下。
    2021-01-01
  • Java tomcat環(huán)境變量及idea配置解析

    Java tomcat環(huán)境變量及idea配置解析

    這篇文章主要介紹了Java tomcat環(huán)境變量及idea配置解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-12-12
  • 在eclipse中中文漢字亂碼的解決方案

    在eclipse中中文漢字亂碼的解決方案

    在本篇文章里小編給大家分享的是關(guān)于在eclipse中中文漢字亂碼的解決方案,有需要的朋友們可以學習下。
    2019-12-12
  • Java中使用Hutool的DsFactory操作多數(shù)據(jù)源的實現(xiàn)

    Java中使用Hutool的DsFactory操作多數(shù)據(jù)源的實現(xiàn)

    在Java開發(fā)中,管理多個數(shù)據(jù)源是一項常見需求,Hutool作為一個全能的Java工具類庫,提供了DsFactory工具,幫助開發(fā)者便捷地操作多數(shù)據(jù)源,感興趣的可以了解一下
    2024-09-09
  • springboot+redis緩存的實現(xiàn)方案

    springboot+redis緩存的實現(xiàn)方案

    本文介紹了Spring Boot與Redis結(jié)合實現(xiàn)緩存的三種方案:注解方式、注解切面類方式和使用樣例,通過這些方案,可以有效地提高應(yīng)用程序的性能和響應(yīng)速度
    2025-03-03
  • springboot通過spel結(jié)合aop實現(xiàn)動態(tài)傳參的案例

    springboot通過spel結(jié)合aop實現(xiàn)動態(tài)傳參的案例

    SpEl 是Spring框架中的一個利器,Spring通過SpEl能在運行時構(gòu)建復雜表達式、存取對象屬性、對象方法調(diào)用等,今天通過本文給大家介紹springboot?spel結(jié)合aop實現(xiàn)動態(tài)傳參,需要的朋友可以參考下
    2022-07-07
  • Java 隨機取字符串的工具類

    Java 隨機取字符串的工具類

    隨機數(shù)在實際中使用很廣泛,比如要隨即生成一個固定長度的字符串、數(shù)字。或者隨即生成一個不定長度的數(shù)字、或者進行一個模擬的隨機選擇等等。Java提供了最基本的工具,可以幫助開發(fā)者來實現(xiàn)這一切
    2014-01-01

最新評論