• java实现带过期时间的缓存


    缓存在我们开发中十分常见,许多框架提供了缓存机制,如果我们自己需要实现一个缓存,该怎么实现呢?

    现在有个需求:我们有个配置信息,只有一份,这个信息我们存储到redis中:键的名称为config,值为json字符串,比如:

    {
        "time":10,
        "type":1,
        "threshold":1000
    }

           假如我们对这个config里面的内容使用十分频繁,但是这个配置信息更改却不怎么频繁,并且这个更改不一定要实时生效,那么我们可以不用每次使用这个配置信息的时候都去查询redis,因为对redis的性能会有所影响。我们考虑到在应用层使用缓存,将配置信息在应用层缓存起来,每隔一分钟自动清空一下缓存,清空缓存之后,下次请求就会访问redis,获取最新的配置信息。当然这之间配置信息可能已经更改,更改之后到应用最近一次从redis获取数据有一个时间间距,这段时间所使用的配置信息可能不是最新的,当然我们可以忍受这一点。

    注意本次博文我们想缓存一个对象,而不是很多数据。

    一:简单实现


    1,首先我们假如已经有了一个查询配置信息的方法:

        public MyConfig getConfig(){
            return JSONObject.parseObject(stringRedisTemplate.opsForValue().get("config"), MyConfig.class);
        }

    上面代码只是演示,部分代码在博文中没有贴出。

    • MyConfig类内容和上面的json字符串对应。
    • get("config")中的config是redis中的键。

    当程序调用上面的getConfig方法,每次都会从redis获取数据,现在我们对代码进行改造。

    2,新建一个缓存类ConfigCache:

    public final class ConfigCache {
    
        private static MyConfig myConfig = null;
    
        private ConfigCache() {
        }
    
        static {
            ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
            executor.scheduleAtFixedRate(() -> {
                myConfig = null;
            }, 0, 60, TimeUnit.SECONDS);
        }
    
        public static MyConfig get() {
            return myConfig;
        }
    
        public static void put(MyConfig newConfig) {
            myConfig = newConfig;
        }
    }

    我们定义了一个缓存类,持有一个要缓存的对象MyConfig,提供获取和设置方法。并且在每隔60秒清空一次该MyConfig对象,这就实现了缓存对象过期时间的功能。

    3,重新编写查询配置信息的代码:

        public MyConfig getConfig(){
            MyConfig myConfig = ConfigCache.get();
            if(myConfig == null){
                myConfig = JSONObject.parseObject(stringRedisTemplate.opsForValue().get("config"), MyConfig.class);
                ConfigCache.put(myConfig);
            }
            return myConfig;
        }

    先查询本地缓存,如果本地缓存为空,则从redis查询,并且保存至本地缓存;如果本地缓存不为空,则直接使用本地缓存。

    到此上面的简单需求我们就实现了。

    二:借用java8 computeIfAbsent 方法优化代码


    image

    上面图片来自《Java 8函数式编程》一书。

    很显然1.3节的内容和图片上面的5-31节代码类似,java8提供了computeIfAbsent 方法简化开发。我们可以提供自己的computeIfAbsent 方法,然后优化代码。

    1,改造缓存类ConfigCache

    public final class ConfigCache {
    
        private static MyConfig myConfig = null;
    
        private ConfigCache() {
        }
    
        static {
            ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
            executor.scheduleAtFixedRate(() -> {
                myConfig = null;
            }, 0, 60, TimeUnit.SECONDS);
        }
    
        public static MyConfig computeIfAbsent(Supplier<MyConfig> supplier) {
            if (myConfig == null) {
                myConfig = supplier.get();
            }
            return myConfig;
        }
    }

    我们删除了get和put方法,新增了computeIfAbsent 方法,该方法需要一个Supplier,它提供一个MyConfig对象。

    computeIfAbsent 代码主要逻辑是如果myConifg不为空,则返回该对象,否则通过Supplier构造一个对象给ConfigCache类的静态属性赋值,并返回该对象。

    2,重新编写查询配置信息的实现的代码:

        public MyConfig getConfig(){
            return ConfigCache.computeIfAbsent(JSONObject.parseObject(stringRedisTemplate.opsForValue().get("config"), MyConfig.class));
        }

    此时查询配置信息的方法就很简单了,和上面图片改造的类似,代码看起来也简洁许多。

     

  • 相关阅读:
    BZOJ_4320_ShangHai2006 Homework_分块
    BZOJ_3362_[Usaco2004 Feb]Navigation Nightmare 导航噩梦_并查集
    BZOJ_2788_[Poi2012]Festival_差分约束+tarjan+floyed
    BZOJ_2795_[Poi2012]A Horrible Poem_hash+暴力
    BZOJ_1598_[Usaco2008 Mar]牛跑步_A*
    [转载]java匿名对象
    [转载]static in Java
    Bat批处理文件入门
    在set中放入自定义类型
    [转载]C++STL概述
  • 原文地址:https://www.cnblogs.com/ye-feng-yu/p/11797123.html
Copyright © 2020-2023  润新知