zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    20145301&20145321&20145335实验三
    20145301《信息安全系统设计基础》第12周学习总结
    20145301&20145321&20145335实验五
    20145240 《信息安全系统设计基础》课程总结
    20145240《信息安全系统设计基础》第十四周学习总结
    20145240《信息安全系统设计基础》第十三周学习总结
    20145240 《信息安全系统设计基础》第六周同学问题总结
    20145240 GDB调试汇编堆栈过程分析
    20145240 《信息安全系统设计基础》实验五 网络通信
    20145240《信息安全系统设计基础》实验四 驱动程序设计
  • 原文地址:https://www.cnblogs.com/intsmaze/p/9477803.html
Copyright © 2011-2022 走看看