java使用Map做缓存你真的用对了吗?弱引用WeakHashMap了解一下
序:使用java的Map做缓存,你是否考虑过容量导致的OOM问题,是否考虑命中率对性能的影响??
应用系统开发中,我们经常会使用redis,memcache等第三方框架做缓存的解决方案,有的时候我们的需求以及应用场景并不是那么复杂,而且交付日期已经秒计了。我们怎么敢在现有的应用中引入第三方框架,火都把头顶烧秃咯。这个时候怎么办,绩效啊,年终奖啊。
关于缓存我们应该考虑什么?-intsmaze
可能大部分人使用缓存都仅仅是取和存操作,但是呢!如果对计算机操作系统有所了解,其实不用看redis的配置文件就知道要考虑容量的问题。比如操作系统中的页面调度的各种FIFO,LRU算法都是为了提高命中率。同样我们在应用中使用缓存也应该考虑命中率和容量问题。尤其是我们使用Java的map做简单的缓存,更是应该考虑。
女神:容量是吗?说的那么高大上,不就new的时候指定一下容量嘛,这么简单
new HashMap<Integer, Byte[]>(100);
intsmaze:您好,你可以尝试往map里面添加101个元素,然后遍历map看看遍历的数据个数是100还是101,HashMap内部有一个数组,会自动扩容的亲。
女神:哎呀,确实。那么我就把HashMap封装一下吧。
private Map<String,String> map=new HashMap<String,String>();
private int len;
public intsmaze(int len)
{
this.len=len;
}
boolean put(String key,String value)
{
if(map.size()==len)
{
return false;
}
else
{
map.put(key, value);
return true;
}
}
intsmaze:您好,这样确实解决了OOM问题,但是我有一个问题不知当讲不当讲,这样做的话,是不是put len次后,后面的数据都不会存储了,get的时候永远只能从get到钱len次的数据,其他的数据要走硬盘去读了?
女神:是的,我把len的大小设置大一点,然后每隔一个小时清空一下map里面的值,不就行了,你为什么要针对我啊?
intsmaze: 额,你这样也可以,但是要在前期花时间调试Map大小,选择一个合适的大小,而且每隔一个小时,mysql等存储都会面临大量的请求,容易引发缓存雪崩。而且如果最求性能的话,这里其实还是有提高的,命中率的高低决定了性能的高低。
女神: 那你想怎么样?咋滴啥?
intsmaze: 这个时候你可以了解一下FIFO,LRU等。如果你用过redis,你应该知道,不你可能知道,redis关于命中率三种策略(FIFO 、LRU、LFU)。所以我们如果要使用Map做缓存,我们也应该考虑一下命中率。后面编不下去了,直接讲这篇文章的重点吧。
WeakHashMap弱引用-intsmaze
WeakHashMap实现了Map接口,使用弱引用作为内部数据的存储方案。WeakHashMap是弱引用的典型应用,可以作为简单的缓存表解决方案。WeakHashMap会在系统内存范围内,保存所有表项目,一旦内存不够,在GC时,没有被引用的表项很快会被清除掉,从而避免系统内存溢出。
关于弱引用我就不讲啦,百度一大堆
Map<Integer, Byte[]> map = null;
map = new WeakHashMap<Integer, Byte[]>();
for (int i = 0; i < 10000; i++) {
Integer integer = new Integer(i);
map.put(integer, new Byte[i]);
}
//-Xmx5M 这个时候发现没有OOM
// -Xmx5M java.lang.OutOfMemoryError: Java heap space
map = new HashMap<Integer, Byte[]>(10);
for (int i = 0; i < 100; i++) {
Integer integer = new Integer(i);
map.put(integer, new Byte[i]);
}
//如果存放在WeakHashMap中的key都存在强引用,那么WeakHashMap就会退化为HashMap。
// -Xmx5M java.lang.OutOfMemoryError: Java heap space
// at cn.intsmaze.collection.MapCase.testWeakHash(MapCase.java:119)
map = new WeakHashMap<Integer, Byte[]>();
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
Integer integer = new Integer(i);
map.put(integer, new Byte[i]);// 如果你看不起我,你可以把这行注释,你将会发现姜还是老的辣,内存溢出是WeakHashMap而不是List导致.
list.add(integer);
}
如果希望在系统中通过WeakHashMap自动清理数据,尽量不要在系统的其他地方强引用WeakHashMap的key,否则,这些key就不会被回收,WeakHashMap也就无法正常释放他们所占用的表项。
线程安全问题-intsmaze
前面已经知道,使用WeakHashMap可以忽略容量问题,提升缓存容量。只是当容量不够时,不会OOM,内部数据会被GC回收。命中率好像没有办法,容我掉一片头发换来深度思考后给出方案。
使用WeakHashMap一般是全局变量,局部变量的应用场景应该没有吧。
观察WeakHashMap源码可以发现,它是线程不安全的,所以在多线程场景该怎么办嘞?
Collections-intsmaze
WeakHashMap<String, String> weakHashMapintsmaze=new WeakHashMap<String, String>();
Map<String, String> intsmaze=Collections.synchronizedMap(weakHashMapintsmaze);
就问你服不服。
ThreadLocal-intsmaze
一个ThreadLocal记录一个weakHashMap,良好的系统是不会不断的创建销毁线程的,而是有线程池进行维护,那么就用ThreadLocal吧。不懂,你可以先关注我,再去百度。
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2mx7vvis5a80k
java使用Map做缓存你真的用对了吗?弱引用WeakHashMap了解一下的更多相关文章
- Java 使用 Map 实现缓存工具
以下代码参考于网上,做了小部分修改. 该代码实现了定时清除临时缓存的功能. 缓存管理类 package com.wbproject.util.cache; import java.time.Local ...
- Redis和MemCache静态Map做缓存区别
本地缓存和分布式缓存 本地缓存:使用自带的map或者guava实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着jvm的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不 ...
- HDOJ(HDU) 2192 MagicBuilding(用Java的Map做了下)
Problem Description As the increase of population, the living space for people is becoming smaller a ...
- 为什么要用 redis 而不用 map 做缓存?
缓存分为本地缓存和分布式缓存.以 Java 为例,使用自带的 map 或者 guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 jvm 的销毁而结束,并且在多实例的情况下,每个实例 ...
- spring+redis的集成,redis做缓存
1.前言 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.我们都知道,在日常的应用中,数据库瓶颈是最容易出现的 ...
- spring-boot集成mybatis,用redis做缓存
网上有很多例子了,执行源码起码有3个,都是各种各样的小问题. 现在做了个小demo,实现spring-boot 用redis做缓存的实例,简单记录下思路,分享下源码. 缓存的实现,分担了数据库的压力, ...
- Java中经常使用缓存Cache机制的实现
缓存,就是将程序或系统常常要调用的对象存在内存中,一遍其使用时能够高速调用,不必再去创建新的反复的实例. 这样做能够降低系统开销.提高系统效率. 缓存主要可分为二大类: 一.通过文件缓存,顾名思义文件 ...
- Spring Boot 2整合Redis做缓存
既然是要用Redis做缓存,自然少不了安装了.但是本文主要讲Spring Boot与Redis整合.安装教程请另行百度! 1.首先是我们的Redis配置类 package com.tyc; impor ...
- springboot2.0+redis实现消息队列+redis做缓存+mysql
本博客仅供参考,本人实现没有问题. 1.环境 先安装redis.mysql 2.springboot2.0的项目搭建(请自行完成),本人是maven项目,因此只需配置,获取相应的jar包,配置贴出. ...
随机推荐
- (python)数据结构---字符串
一.概述 由一个个字符组成的有序序列. 使用单引号.双引号.三引号引住的字符序列. 不可变.线性的数据结构. 二.字符串的相关操作 1.元素访问----下标 字符串是线性的数据结构,可以使用索引去访问 ...
- CSS杂谈(1)图
- spring4笔记----常见的java的字符类型与xml匹配
private List<String> schools; <property name="schools"> <list> <value ...
- 注入攻击(SQL注入防御)
正确的防御SQL注入 sql注入的防御不是简单只做一些用户输入的escape处理,这样是不够的,只是提高了攻击者的门槛而已,还是不够安全. 例如 mysql_real_escape_string()函 ...
- GitHub-暂存区与版本回退
参考博文:廖雪峰Git教程 1. 工作区和暂存区 Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念. 1.1. 工作区(Working Directory) 就是你在电脑里能看到的目录 ...
- Java中使用elasticsearch搜索引擎实现简单查询、修改等操作-已在项目中实际应用
以下的操作环境为:jdk:1.8:elasticsearch:5.2.0 maven架包下载坐标为: <dependency> <groupId>org.elasticsear ...
- 2018-10-18读文献总结之DCB码分多址、零基线、信号产生
---恢复内容开始--- 今天心血来潮,想开始把自己读文献的过程和每篇文献的收获总结一下,不知道CSDN怎么回事,一直登陆不进去,搞得我注册了一个博客园的账户,博客园新注册的还需要认证,但是很快,所以 ...
- 在线编辑器ACE Editor的使用
ACE 是一个开源的.独立的.基于浏览器的代码编辑器,可以嵌入到任何web页面或JavaScript应用程序中.ACE支持超过60种语言语法高亮,并能够处理代码多达400万行的大型文档.ACE开发团队 ...
- SQLAlchemy 嵌套事务的解决方案
sqlachemy 是python的orm框架,在使用一段时间后,我们通常会出现事务嵌套的情况,看到很多人写代码的时候,居然是session到处传递,这无疑是加大了代码之间的耦合度. 案例: def ...
- CUDA Fortran for Scientists and Engineers第二版翻译
下午听朋友说,NV把<CUDA Fortran for Scientists and Engineers>的出版权卖给了国内某出版商.第一反应是我们三翻译的岂不是白翻译了.第二 ...