java map 缓存_缓存用于

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


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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 2022年南京Java培训机构排名,实力突出遥遥领先

    2022年南京Java培训机构排名,实力突出遥遥领先2022年南京Java培训机构排名,实力突出遥遥领先近日,中国权威机构公布了2022年南京Java培训机构排名,本次排名第一的机构仍是动力节点,在2021年中,动力节点在Java培训机构排名中始终始名列前茅,那为什么动力节点在Java培训机构排名中始终名列前茅呢?一生只做一件事,动力节点为Java而生贵在专一多元化发展是人性的冲动,最容易干扰企业的方向。一个教育企业真正想要做大做强就要突破人骨子里的“贪婪”,专注到自己核心竞争力上,才会有不断提升持续进步的基础。动力节点从2009年成立至

    2022年10月3日
  • 微信小程序跳转传值(微信怎样打开小程序)

    前情:首先我们有这么一种需求,就是我在一个列表中点击了某个item,跳转到详情界面,那么我就需要把item的实体数据从列表页面传递到详情页面,那么我们来看看微信小程序给我们提供的API:先看api:这里大家可以清楚看到api中说到的如何传递参数,其实它这里指的参数仅仅是一些普通的数据类型具体分析:这里我们要传递的实体是object类型,那么我们需要先把实体转…

    2022年4月12日
  • toast弹窗什么意思_app加弹窗软件

    toast弹窗什么意思_app加弹窗软件//界面toast提示/*使用方法Toast(‘这是一个弹框’,2000)*/functionToast(msg,duration){ duration=isNaN(duration)?3000:duration; varm=document.createElement(‘div’); m.innerHTML=msg; m.style.cssText=…

    2022年9月24日
  • Linux的#和$区别[通俗易懂]

    Linux的#和$区别[通俗易懂]【#】代表root权限【$】代表普通用户如果更改了/etc/profile,或~/.bashrc等文档,可以用任何符号来代替它们。linux窗口下的【root@locate~】其中的【~】代

    2022年8月6日
  • pycharm安装、首次使用及汉化

    pycharm安装、首次使用及汉化一、下载pycharm安装包打开PyCharm的官方下载地址:http://www.jetbrains.com/pycharm/download/#section=windows打开网站后的界面展示如图:professional是专业版,可以免费试用,community是社区版,是免费开源的,推荐下载使用社区版。下载后的PyCharm:二、安装1.双击应用程序后点击【Next】…

    2022年5月26日
  • 成员函数

    成员函数在C++中,允许在结构体中定义函数,该函数称为“成员函数”。描述形式如下:struct结构名{数据成员成员函数};例题:身高问题输入n个学生的信息,每个学生的信息包括姓名、身高、学号。变

    2022年7月3日

发表回复

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

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