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

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

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

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

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ù)一致性,尤其適合分布式微服務架構(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<>();
    // 延遲任務執(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并設置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);
    }
}    

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

相關文章

  • 十種JAVA排序算法實例

    十種JAVA排序算法實例

    本文件講了十種JAVA排序方法(冒泡(Bubble)排序——相鄰交換 、選擇排序——每次最小/大排在相應的位置 、插入排序——將下一個插入已排好的序列中 、殼(Shell)排序——縮小增量 、歸并排序 、快速排序 、堆排序 、拓撲排序 、錦標賽排序 、基數(shù)排序)的使用,并提供了實例代碼可參考
    2013-11-11
  • 詳解Java的JDBC API的存儲過程與SQL轉(zhuǎn)義語法的使用

    詳解Java的JDBC API的存儲過程與SQL轉(zhuǎn)義語法的使用

    這篇文章主要介紹了詳解Java的JDBC API的存儲過程與SQL轉(zhuǎn)義語法的使用,JDBC是Java用于連接使用各種數(shù)據(jù)庫的API,需要的朋友可以參考下
    2015-12-12
  • Springboot啟動原理詳細講解

    Springboot啟動原理詳細講解

    這篇文章主要介紹了SpringBoot啟動原理的分析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • springMvc注解之@ResponseBody和@RequestBody詳解

    springMvc注解之@ResponseBody和@RequestBody詳解

    本篇文章主要介紹了springMvc注解之@ResponseBody和@RequestBody詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Java 進程執(zhí)行外部程序造成阻塞的一種原因

    Java 進程執(zhí)行外部程序造成阻塞的一種原因

    前一陣子在研究文檔展示時使用了java進程直接調(diào)用外部程序,其中遇到一個問題花了好長時間才解決,這個問題就是外部程序直接執(zhí)行沒什么問題,但是當使用Java進程執(zhí)行時外部程序就阻塞在那兒不動了。而且這個外部程序在處理某些文件時使用Java進程執(zhí)行是沒問題的
    2014-03-03
  • Java springboot Mongodb增刪改查代碼實例

    Java springboot Mongodb增刪改查代碼實例

    這篇文章主要介紹了Java springboot Mongodb增刪改查代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • 如何用java獲取指定日期是第幾周

    如何用java獲取指定日期是第幾周

    這篇文章主要給大家介紹了關于如何用java獲取指定日期是第幾周的相關資料,在開始之前我們需要先了解如何獲取當前日期所在的年份以及第幾周,在Java中可以使用Calendar類來獲取這些信息,需要的朋友可以參考下
    2023-09-09
  • SpringBoot在線代碼修改器的問題及解決方法

    SpringBoot在線代碼修改器的問題及解決方法

    這篇文章主要介紹了SpringBoot在線代碼修改器的問題及解決方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • 使用SpringAOP自定義權限控制注解的實現(xiàn)示例

    使用SpringAOP自定義權限控制注解的實現(xiàn)示例

    本文主要介紹了使用SpringAOP自定義權限控制注解的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-08-08
  • Java數(shù)組越界問題實例解析

    Java數(shù)組越界問題實例解析

    這篇文章主要介紹了Java數(shù)組越界問題實例解析,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10

最新評論

丹江口市| 沈丘县| 成武县| 黔西县| 洪江市| 巩留县| 于田县| 辰溪县| 喀喇| 宣化县| 永丰县| 荔浦县| 景谷| 建始县| 沙河市| 沙雅县| 明溪县| 安新县| 芷江| 永吉县| 克山县| 湟源县| 汉源县| 四子王旗| 宁波市| 林芝县| 漳平市| 乌鲁木齐市| 米易县| 那曲县| 新河县| 中方县| 新龙县| 益阳市| 商南县| 图片| 陈巴尔虎旗| 霸州市| 体育| 泌阳县| 高阳县|