java map 缓存_缓存用于

java map 缓存_缓存用于缓存什么是缓存?平常的开发项目中,多多少少都会使用到缓存,因为一些数据我们没有必要每次查询的时候都去查询到数据库。缓存的使用场景:在Java应用中,对于访问频率高,更新少的数据,通常的方案是将这类数据加入缓存中,相对从数据库中读取,读缓存效率会有很大提升。在集群环境下,常用的分布式缓存有Redis等。但在某些业务场景上,可能不需要去搭建一套复杂的分布式缓存系统,在单机环境下,通常是会希望使用内部的缓存(LocalCache)。使用map缓存方案:基于ConcurrentHashMap实现数

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

缓存

什么是缓存?
平常的开发项目中,多多少少都会使用到缓存,因为一些数据我们没有必要每次查询的时候都去查询到数据库。

缓存的使用场景:
在Java应用中,对于访问频率高,更新少的数据,通常的方案是将这类数据加入缓存中,相对从数据库中读取,读缓存效率会有很大提升。
在集群环境下,常用的分布式缓存有Redis等。但在某些业务场景上,可能不需要去搭建一套复杂的分布式缓存系统,在单机环境下,通常是会希望使用内部的缓存(LocalCache)。

使用map缓存

方案:

  • 基于ConcurrentHashMap实现数据缓存,实现线程安全要求
  • SoftReference:当内存不够的时候,GC会回收SoftReference所引用的对象

SoftReference是软引用,它保存的对象实例,除非JVM即OutOfMemory,否则不会被GC回收。这个特性使得它特别适合设计对象Cache。对于Cache,我们希望被缓存的对象最好始终常驻内存,但是如果JVM内存吃紧,为了不发生OutOfMemoryError导致系统崩溃,必要的时候也允许JVM回收Cache的内存,待后续合适的时机再把数据重新Load到Cache中。这样可以系统设计得更具弹性。

代码如下:

/** * 使用map做缓存 */
public class MapCache { 
   
	//定义扫描时间参数
    private static final int CLEAN_TIME_PARAMETER = 5;

    private final ConcurrentHashMap<String, SoftReference<CacheObject>> cache = new ConcurrentHashMap<>();

	/** * 在构造函数中,创建一个守护程序线程,每5秒扫描一次并清理过期的对象。 */
    public MapCache(){ 
   
        Thread cleanerThread = new Thread(()->{ 
   
            //获取线程中断状态
            while (!Thread.currentThread().isInterrupted()) { 
   
                try { 
   
                    Thread.sleep(CLEAN_TIME_PARAMETER * 1000);
                    cache.entrySet().removeIf(entry ->
                            Optional.ofNullable(entry.getValue())
                                    .map(SoftReference::get)
                                    .map(CacheObject::isExpired)
                                    .orElse(false));
                } catch (InterruptedException e) { 
   
                    Thread.currentThread().interrupt();
                }
            }
        });
        cleanerThread.setDaemon(true);
        cleanerThread.start();
    }

    public void add(String key, Object value, long periodInMillis) { 
   
        if(key == null){ 
   
            return;
        }
        if(value == null){ 
   
            cache.remove(key);
        }else { 
   
            long expiryTime = System.currentTimeMillis() + periodInMillis;
            cache.put(key, new SoftReference<>(new CacheObject(value, expiryTime)));
        }
    }

    public void remove(String key) { 
   
        cache.remove(key);
    }

    public Object get(String key) { 
   
        return Optional.ofNullable(cache.get(key)).map(SoftReference::get).filter(cacheObject -> !cacheObject.isExpired()).map(CacheObject::getValue).orElse(null);
    }

    public void clear() { 
   
        cache.clear();
    }

    public long size() { 
   
        return cache.entrySet().stream().filter(entry -> Optional.ofNullable(entry.getValue()).map(SoftReference::get).map(cacheObject -> !cacheObject.isExpired()).orElse(false)).count();
    }


    /** * 缓存对象value */
    private static class CacheObject { 
   
        private Object value;
        private long expiryTime;

        private CacheObject(Object value, long expiryTime) { 
   
            this.value = value;
            this.expiryTime = expiryTime;
        }

        boolean isExpired() { 
   
            return System.currentTimeMillis() > expiryTime;
        }

        public Object getValue() { 
   
            return value;
        }

        public void setValue(Object value) { 
   
            this.value = value;
        }
    }
}

测试类:

public class Test { 
   
    public static void main(String[] args) throws InterruptedException { 
   
        MapCache mapCache = new MapCache();
        mapCache.add("10001", "111111", 5 * 1000);
        mapCache.add("10002", "222222", 5 * 1000);
        mapCache.add("10003", "333333", 5 * 1000);
        System.out.println("从缓存中取出值:" + mapCache.get("10001"));
        Thread.sleep(5000L);
        System.out.println("5秒钟过后");
        // 5秒后数据自动清除了
        System.out.println("从缓存中取出值:" + mapCache.get("10001"));
     
    }
}

Optional类

关于Optional类,是jdk1.8引进的新特性,主要解决的问题是臭名昭著的空指针异常(NullPointerException)
参考文章:Optional类的学习,理解,使用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/188445.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • PyCharm社区版安装教程和环境配置及使用[通俗易懂]

    PyCharm社区版安装教程和环境配置及使用[通俗易懂]一、PyCharm官网下载访问官网地址:https://www.jetbrains.com/pycharm/点击首页【Download】按钮,进入下载页面,选择Community下的【Download】,如图:点击后进入“ThankyoufordownloadingPyCharm!”页面,选择“另存为”,如图:选择本地目录路径,点击【保存】,开始下载:双击本地的PyCharm安装包,进入安装首页,点击【Next>】按钮,如图:进入“ChooseInstallLocati

    2022年8月28日
    1
  • Java web环境配置和Servlet实例HelloWorld<转自banama的个人博客>

    Java web环境配置和Servlet实例HelloWorld<转自banama的个人博客>

    2021年9月7日
    60
  • 短期负荷预测(一)概念

    短期负荷预测(一)概念根据预测的时间跨度的长短,电力负荷预测(以下简称负荷预测)问题可以粗略分为长期和短期的预测。由于不同应用场景中对时间跨度的需求不同,对“长期”和“短期”的定义也有所不同。例如,国家电网发展战略制定者将

    2022年7月3日
    37
  • mybatis多条件查询sql_sql模糊查询多个条件

    mybatis多条件查询sql_sql模糊查询多个条件步骤1:先运行,看到效果,再学习步骤2:模仿和排错步骤3:在前一步的基础上进行步骤4:模糊查询步骤5:多条件查询步骤1:先运行,看到效果,再学习老规矩,先下载下载区(点击进入)的可运行项目,配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。步骤2:模仿和排错在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。模仿过程难免代码有出入,导致无法得到…

    2022年9月4日
    2
  • 高并发解决方案相关面试题

    高并发解决方案相关面试题什么是DNS解析域名DNS域名解析就是讲域名转化为不需要显示端口(二级域名的端口一般为80)的IP地址,域名解析的一般先去本地环境的host文件读取配置,解析成对应的IP地址,根据IP地址访问对应的服务器。若host文件未配置,则会去网络运营商获取对应的IP地址和域名.什么是NginxNginx是一个高级的轻量级的web服…

    2022年5月22日
    29
  • 树莓派4B设置USB启动

    树莓派4B设置USB启动千呼万唤始出来!官方在2020-05-15发布了一个4B的beta版EEPROM固件更新,这次更新终于增加了期待已久的USB引导功能,今天这个教程就来讲一下如何使用USB而脱离SD卡启动树莓派4B。

    2022年5月18日
    87

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号