二级缓存封装实现,面对压测轻松

本文介绍了一个内存缓存的具体实现方式,包括使用ConcurrentHashMap作为缓存容器,通过定时任务清理过期缓存,并采用随机误差防止缓存雪崩。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.test.core.cache.impl;

import de.hybris.platform.util.Config;

import org.apache.log4j.Logger;

import java.security.SecureRandom;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

public class MemoryCache {

    private static final Logger log = Logger.getLogger(MemoryCache.class.getName());

    private static ConcurrentHashMap cache = new ConcurrentHashMap<>(16);

    private static SecureRandom random = new SecureRandom();

    public static final long STD = random.nextInt(MemoryCacheConstant.DEFAULT_STD);

    /**

     * 定时移除缓存的线程

     */

    private static ClearCacheThread clearCacheThread = new ClearCacheThread(cache);

    static {

        clearCacheThread.setName(MemoryCacheConstant.CLEAR_CACHE_THREAD_NAME);

        clearCacheThread.setDaemon(true);

        clearCacheThread.start();

    }

    private static void cache(String key, CacheBO cacheFromMemory) {

        cache.put(key, cacheFromMemory);

    }

    public static T> T getValue(String key, RefreshCacheFunctionT> refreshCacheFunction) {

        final long timeToLive = Config.getLong("memory.cache.time.stamp",MemoryCacheConstant.DEFAULT_TIME_TO_LIVE);

        return getValue(key, timeToLive + STD, refreshCacheFunction);

    }

    public static T> T getValue(String key, long timeToLive, RefreshCacheFunctionT> refreshCacheFunction) {

        T value = null;

        CacheBOT> cacheFromMemory = MemoryCache.getValue(key);

        boolean valid = false;

        long now = System.currentTimeMillis();

        if (cacheFromMemory != null) {

            //防缓存雪崩,timeToLive会包含随机误差

            if (cacheFromMemory.getTimestamp() != null && now - cacheFromMemory.getTimestamp() < timeToLive) {

                valid = true;

            }

        }

        if (!valid) {

            try {

                //intern确保字符串直接从常量池获取,避免stringBuilder等new操作返回不同的string对象

                synchronized (key.intern()) {

                    CacheBOT> cacheFromMemoryNew = MemoryCache.getValue(key);

                    if (cacheFromMemoryNew == null || cacheFromMemoryNew.getTimestamp() == null || cacheFromMemoryNew.getTimestamp() < now) {

                        value = refreshCacheFunction.refresh();

                        //添加二级缓存

                        cacheFromMemoryNew = new CacheBO<>();

                        cacheFromMemoryNew.setValue(value);

                        cacheFromMemoryNew.setTimestamp(System.currentTimeMillis());

                        MemoryCache.cache(key, cacheFromMemoryNew);

                    }

                    value = cacheFromMemoryNew.getValue();

                }

            } catch (Exception e) {

                log.error("刷新二级缓存失败", e);

            }

        } else {

            value = cacheFromMemory.getValue();

        }

        return value;

    }

    private static T> T getValue(String key) {

        return (T) cache.get(key);

    }

    public static void pushCache(String key,Map value){

        CacheBO> cacheFromMemoryNew = new CacheBO<>();

        cacheFromMemoryNew.setValue(value);

        cacheFromMemoryNew.setTimestamp(System.currentTimeMillis());

        MemoryCache.cache(key, cacheFromMemoryNew);

    }

}

/**

 * @author Zhi.Dong

 * 定时清除二级缓存的无效数据

 */

class ClearCacheThread extends Thread {

    private ConcurrentHashMap cache;

    private static final Logger log = Logger.getLogger(ClearCacheThread.class.getName());

    ClearCacheThread(ConcurrentHashMap cache) {

        this.cache = cache;

    }

    @Override

    public void run() {

        try {

            while (true) {

                try {

                    clearCache();

                    Thread.sleep(MemoryCacheConstant.DEFAULT_TIME_TO_EXE_CLEAR);

                } catch (Exception e) {

                    log.error("ClearCacheThread inLoop 清除缓存失败", e);

                }

            }

        } catch (Exception e) {

            log.error("ClearCacheThread 清除缓存失败", e);

        }

    }

    /**

     * 清除缓存里过期的数据

     */

    private void clearCache() {

        long now = System.currentTimeMillis();

        for (Map.Entry entry : cache.entrySet()) {

            CacheBO v = entry.getValue();

            boolean clear = true;

            //数据有效则不删除,此有效时间不同于缓存查询的有效时间

            //仅用于清除过期时间已过很久的数据

            if (v != null) {

                if (v.getTimestamp() != null && now - v.getTimestamp() < MemoryCacheConstant.DEFAULT_TIME_TO_CLEAR) {

                    clear = false;

                }

            }

            if (clear) {

                log.info(String.format("clearCache success,key=%s", entry.getKey()));

                cache.remove(entry.getKey());

            }

        }

    }

}

MemoryCacheConstant

package com.test.core.cache.impl;

/**

 *

 * 二级缓存相关常量

 */

public interface MemoryCacheConstant {

    /**

     * 默认缓存有效期,10s

     */

    Long DEFAULT_TIME_TO_LIVE = 10000L;

    /**

     * 默认防雪崩随机误差,5s

     */

    Integer DEFAULT_STD = 5000;

    /**

     * 定时线程名称

     */

    String CLEAR_CACHE_THREAD_NAME = "clear-memory-cache-thread";

    /**

     * 默认缓存清除时间,5分钟

     */

    Long DEFAULT_TIME_TO_CLEAR = 5 * 60 * 1000L;

    /**

     * 默认缓存清除触发间隔,60s

     */

    Long DEFAULT_TIME_TO_EXE_CLEAR = 60 * 1000L;

}

RefreshCacheFunction

  package com.test.core.cache.impl;

public interface RefreshCacheFunctionT> {

    /**

     * 返回用于刷新二级缓存的结果

     * @return

     */

    T refresh();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值