如何实现一个内存缓存工具类(CacheUtil)

实现一个内存缓存工具类,可以是单机缓存。

  1. 有超时机制。
  2. 能控制总条数。
  3. 实现各种策略的更新机制。
  4. 效率越高越好。

这个是最近组内集体学习出的一个简单练习题,借鉴了一下网友的,自己写的代码如下:

/**
 * 缓存类
 */
package com.hao.cache;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;

/**
 * 描述:设置一个缓存策略
 * 
 * @since 2019年9月25日 下午6:57:12
 * @author 
 */
public class CacheUtil {

    /**
     * 隐藏构造器
     */
    private CacheUtil() {
    }

    // 主缓存,用于存放需要存放的对象
    private static final Map<String, Object> CACHE_MAP = new HashMap<String, Object>();

    // 用户存放过期的时间
    private static final Map<String, Long> TIME_MAP = new HashMap<String, Long>();

    /** 保存对象的长度 (个数) **/
    private static final int OBJ_LENGTH = 1000;

    /** 保存对象的大小(以B为单位,包括了,过期时间的大小和对象的大小) **/
    private static final int OBJ_SIZE = 1024 * 1024;

    /**
     * 刷新缓存,清除过期数据(同步处理)
     * 
     * @throws Exception
     *             异常
     */
    public static void flushPastCacheSyn() {

        // 迭代器删除过期数据(删除缓存时也)
        Iterator<Map.Entry<String, Object>> cacheIterator = CACHE_MAP.entrySet().iterator();

        while (cacheIterator.hasNext()) {

            Map.Entry<String, Object> entry = cacheIterator.next();

            String key = entry.getKey();

            if (TIME_MAP.containsKey(key)) {

                // 获取过期时间
                long expireTime = TIME_MAP.get(key);

                // 已经过期则删除
                if (System.currentTimeMillis() > expireTime) {

                    // 缓存内容
                    cacheIterator.remove();
                    // 删除截止时间
                    TIME_MAP.remove(key);
                }
            }
        }
    }

    /**
     * 刷新缓存,清除过期数据(异步处理)
     * 
     * @throws Exception
     *             异常
     */
    public static void flushPastCacheAsyn() {

        // 先删除过期数据
        RunTemp temp = new RunTemp();
        temp.start();
    }

    /**
     * 清除缓存,清空数据
     */
    public static void clearPastCache() {

        CACHE_MAP.clear();
        TIME_MAP.clear();
    }

    /**
     * 设置value永久的
     * 
     * @param key
     *            key
     * @param value
     *            value
     * @throws Exception
     *             异常
     */
    public static void set(String key, Object value) throws Exception {

        // 添加数据时,先删除过期数据,这样可以做到动态更新,在SpringBoot中可以用线程池管理,但是此处这么写显然不是很合适,所以注掉
        // RunTemp temp = new RunTemp();
        // temp.start();

        // 不过期也就是默认100年后过期
        final long expiretime = System.currentTimeMillis() + 100 * 365 * 24 * 60 * 60 * 1000;
        CACHE_MAP.put(key, value);
        TIME_MAP.put(key, expiretime);

        // 不能存储
        if (!canCacheObject(key)) {
            throw new Exception("超长超大了");
        }
    }

    /**
     * 设置value
     * 
     * @param key
     *            key
     * @param value
     *            value
     * @param ms
     *            毫秒过期时间
     * @throws Exception
     *             异常
     */
    public static void set(final String key, Object value, int ms) throws Exception {

        // 先删除过期数据
        // RunTemp temp = new RunTemp();
        // temp.start();

        final long expireTime = System.currentTimeMillis() + ms;

        CACHE_MAP.put(key, value);
        TIME_MAP.put(key, expireTime);

        // 不能存储
        if (!canCacheObject(key)) {
            throw new Exception("超长超大了");
        }
    }

    /**
     * 获取指定的value,如果key不存在或者已过期,则返回null
     * 
     * @param key
     *            key
     * @return 结果
     * @throws Exception
     *             异常
     */
    public static Object get(String key) throws Exception {

        // 判断key是否存在
        if (!CACHE_MAP.containsKey(key) || !TIME_MAP.containsKey(key)) {
            return null;
        }

        // 缓存失效,已过期
        if (TIME_MAP.get(key) < System.currentTimeMillis()) {

            // 如果获取的是已过期的key,直接将其删除
            CACHE_MAP.remove(key);
            TIME_MAP.remove(key);

            return null;
        }

        // 返回value
        return CACHE_MAP.get(key);
    }

    /**
     * 
     * 能够否继续储存
     * 
     * @param key
     *            对象key
     * @return 能否存储
     * @throws Exception
     *             异常
     */
    public static boolean canCacheObject(final String key) throws Exception {

        // 超长超大(最好在put前判断大小,可以防止map被撑爆,而put后判断可以做到精准判断,这里以实现功能为主)
        if (CACHE_MAP.size() > OBJ_LENGTH || getCacheSize(CACHE_MAP, TIME_MAP) > OBJ_SIZE) {

            // 如果超大,超长了,删除刚填进去的key
            CACHE_MAP.remove(key);
            TIME_MAP.remove(key);

            return false;
        }
        return true;
    }

    /**
     * 描述:异步删除过期了的缓存
     * 
     * @since 2019年9月26日 上午10:01:34
     * @author
     */
    private static class RunTemp extends Thread {

        /**
         * 多线程异步删除过期缓存(每次运行添加数据时执行一次清除操作,若是在SpringBoot项目中可以利用定时器实现定时清除,此处仅做模拟,所以在添加数据的时候清理一下)
         */
        @Override
        public void run() {

            // 删除过期内容
            flushPastCacheSyn();
        }
    }

    /**
     * key是否存在
     * 
     * @param key
     *            key
     * @return 是否存在
     * @throws Exception
     *             异常
     */
    public static boolean isExistKey(String key) throws Exception {
        return CACHE_MAP.containsKey(key);
    }

    /**
     * 值是否存在
     * 
     * @param value
     *            value
     * @return 是否存在
     * @throws Exception
     *             异常
     */
    public static boolean isExistValue(String value) throws Exception {
        return CACHE_MAP.containsValue(value);
    }

    /**
     * @param maps
     *            多个map的内存总大小(以字节B为单位)
     * @return 返回map的所占内存大小
     * @throws IOException
     *             异常
     */
    @SafeVarargs
    public static int getCacheSize(Map<String, ? extends Object>... maps) throws IOException {

        int size = 0;

        A: for (Map<String, ? extends Object> map : maps) {

            // 判断map是否为空
            if (null == map || map.size() < 0) {
                break A;
            }
            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;

            try {
                bos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(bos);

                oos.writeObject(map);

                // 获取字节大小(单位为B)
                byte[] byteArray = bos.toByteArray();

                size += byteArray.length;
            } catch (IOException e) {

                // 打印异常
                e.printStackTrace();
            } finally {
                if (bos != null) {
                    bos.close();
                }
                if (oos != null) {
                    oos.close();
                }
            }
        }

        return size;
    }

    public static void main(String[] args) throws Exception {

        for (int i = 0; i < 10000; i++) {

            String str = "i" + new Random().nextInt(666666);
            CacheUtil.set(str, "寺东立国际阿三哥夹哦为根据欧舒丹就给你辣酸奶刚看完那三个克拉斯DNF进拉萨的寄过来");
            Object object = CacheUtil.get(str);
            System.out.println(i);
            System.out.println(object);
        }

        CacheUtil.set("nihao", "真的", 12345);

        // clearPastCache();
        CacheUtil.set("zhen", "最好的我们");

        int cacheSize1 = getCacheSize(CACHE_MAP);
        int cacheSize2 = getCacheSize(TIME_MAP);
        // int objectMapBytes = getObjectMapBytes(CACHE_MAP);
        int cacheSize = getCacheSize(CACHE_MAP, TIME_MAP);
        System.out.println("文件大小cache:" + cacheSize1);
        System.out.println("文件大小time:" + cacheSize2);
        // System.out.println("文件大小cache:" + objectMapBytes);
        System.out.println("文件大小cache+time:" + cacheSize);

        for (int i = 0; i < 300; i++) {
            //
            Thread.sleep(1000);
            Object object = CacheUtil.get("nihao");
            System.out.println(object);
            System.out.println(CacheUtil.get("zhen"));
            System.out.println("*************");
        }

        System.out.println("完了**************完了");
    }
}

总结:该工具类的基本骨架是有了,但是还有很大的优化区间,且性能实在是堪忧,希望大家批评指正。

参考:https://blog.csdn.net/liurui50/article/details/100106038

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我可以为你提供一个Redis缓存工具类的示例: import redis class RedisCache: def __init__(self, host, port, db): self.redis = redis.StrictRedis(host=host, port=port, db=db) def get(self, key): return self.redis.get(key) def set(self, key, value): self.redis.set(key, value) def delete(self, key): self.redis.delete(key) def flushall(self): self.redis.flushall() ### 回答2: Redis缓存工具类一个用于简化和优化Redis缓存操作的工具类。下面是一个简单的示例: ```java import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class RedisCacheUtil { private static JedisPool jedisPool; /** * 初始化Jedis连接池 */ static { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(100); // 最大连接数 config.setMaxIdle(20); // 最大空闲连接数 config.setTestOnBorrow(true); // 尝试借用一个连接时,是否进行有效性检测 jedisPool = new JedisPool(config, "localhost", 6379); // Redis连接信息 } /** * 从连接池获取Jedis实例 */ public static Jedis getJedis() { return jedisPool.getResource(); } /** * 将Jedis实例返回到连接池 */ public static void closeJedis(Jedis jedis) { if (jedis != null) { jedis.close(); } } /** * 设置缓存 */ public static void set(String key, String value) { Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.set(key, value); } finally { closeJedis(jedis); } } /** * 根据key获取缓存值 */ public static String get(String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.get(key); } finally { closeJedis(jedis); } } /** * 删除缓存 */ public static void delete(String key) { Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.del(key); } finally { closeJedis(jedis); } } } ``` 使用该工具类,可以通过简单的方法调用来实现Redis缓存的各种操作。示例如下: ```java public class RedisDemo { public static void main(String[] args) { RedisCacheUtil.set("key1", "value"); // 设置缓存 String value = RedisCacheUtil.get("key1"); // 获取缓存 System.out.println(value); RedisCacheUtil.delete("key1"); // 删除缓存 value = RedisCacheUtil.get("key1"); // 获取缓存 System.out.println(value); // 输出null } } ``` 通过使用这个简单的Redis缓存工具类,可以方便地进行Redis缓存的操作,提高缓存的效率和可维护性。当然,实际的缓存操作可以根据具体需求进行扩展和优化。 ### 回答3: Redis缓存工具类是用于简化与Redis数据库交互的工具。下面是一个示例实现: ``` import redis import pickle class RedisCache: def __init__(self, host, port, db): self.redis = redis.Redis(host=host, port=port, db=db) def set(self, key, value, expire=None): pickled_value = pickle.dumps(value) self.redis.set(key, pickled_value) if expire: self.redis.expire(key, expire) def get(self, key): pickled_value = self.redis.get(key) if pickled_value is not None: value = pickle.loads(pickled_value) return value return None def delete(self, key): self.redis.delete(key) def exists(self, key): return self.redis.exists(key) ``` 使用示例: ``` cache = RedisCache(host='localhost', port=6379, db=0) # 设置缓存 cache.set('user:1', {'name': 'Alice', 'age': 25}, expire=3600) # 获取缓存 user = cache.get('user:1') print(user) # 输出: {'name': 'Alice', 'age': 25} # 删除缓存 cache.delete('user:1') # 检查缓存是否存在 if cache.exists('user:1'): print('缓存存在') else: print('缓存不存在') ``` 这个简单的Redis缓存工具类封装了常用的操作方法,如set、get、delete和exists,并使用pickle模块将Python对象序列化成字符串再存储到Redis数据库中,以实现缓存数据的存储和获取。还可以通过设置过期时间来控制缓存的有效期。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值