一文搞定WeakHashMap

打印 上一主题 下一主题

主题 619|帖子 619|积分 1867

写在前面

在缓存场景下,由于内存是有限的,不能缓存所有对象,因此就须要一定的删除机制,淘汰掉一些对象。这个时候可能很快就想到了各种Cache数据逾期策略,目前也有一些优秀的包提供了功能丰富的Cache,比如Google的Guava Cache,它支持数据定期逾期、LRU、LFU等策略,但它仍然有可能会导致有用的数据被淘汰,没用的数据迟迟不淘汰(如果策略利用适当的情况下这都是小概率事件)。
现在有种机制,可以让Cache里不用的key数据自动清算掉,用的还留着,不会出现误删除。而WeakHashMap 就实用于这种缓存的场景,由于它有自清算机制!
如果让你手动实现一种自清算的HashMap,可以怎么做?首先肯定是想办法先知道某个Key肯定没有在用了,然后清算掉HashMap中没有在用的对应的K-V。在JVM里一个对象没用了是指没有任何其他有用对象直接或者间接实行它,详细点就是在GC过程中它是GCRoots不可达的。而某个弱引用对象所指向的对象如果被判定为垃圾对象,Jvm会将该弱引用对象放到一个ReferenceQueue里,只须要看下这个Queue里的内容就知道某个对象另有没有用了。
WeakHashMap概述

从WeakHashMap名字也可以知道,这是一个弱引用的Map,当进行GC回收时,弱引用指向的对象会被GC回收。
WeakHashMap正是由于利用的是弱引用,因此它的对象可能被随时回收。更直观的说,当利用 WeakHashMap 时,即使没有显示的添加或删除任何元素,也可能发生如下情况:

  • 调用两次size()方法返回差别的值;
  • 两次调用isEmpty()方法,第一次返回false,第二次返回true;
  • 两次调用containsKey()方法,第一次返回true,第二次返回false,尽管两次利用的是同一个key;
  • 两次调用get()方法,第一次返回一个value,第二次返回null,尽管两次利用的是同一个对象。

从上图可以看出:

  • WeakHashMap继承于AbstractMap,并且实现了Map接口。
  • WeakHashMap是哈希表,但是它的键是"弱键"。WeakHashMap中保护几个紧张的成员变量:table, size, threshold, loadFactor, modCount, queue。

    • table是一个Entry[]数组类型,而Entry现实上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。
    • size是Hashtable的大小,它是Hashtable生存的键值对的数量。
    • threshold是Hashtable的阈值,用于判定是否须要调整Hashtable的容量。threshold的值="容量*加载因子"。
    • loadFactor就是加载因子。
    • modCount是用来实现fail-fast机制的
    • queue生存的是“已被GC清除”的“弱引用的键”。

基本用法
  1. WeakHashMap < String, String > weakHashMap = new WeakHashMap < > (10);
  2. String key0 = new String("str1");
  3. String key1 = new String("str2");
  4. String key2 = new String("str3");
  5. // 存放元素
  6. weakHashMap.put(key0, "data1");
  7. weakHashMap.put(key1, "data2");
  8. weakHashMap.put(key2, "data3");
  9. System.out.printf("weakHashMap: %s\n", weakHashMap);
  10. // 是否包含某key
  11. System.out.printf("contains key str1 : %s\n", weakHashMap.containsKey(key0));
  12. System.out.printf("contains key str2 : %s\n", weakHashMap.containsKey(key1));
  13. // 移除key
  14. weakHashMap.remove(key0);
  15. System.out.printf("weakHashMap after remove: %s\n", weakHashMap);
  16. // 这意味着"弱键"key1再没有被其它对象引用,调用gc时会回收WeakHashMap中与key1对应的键值对
  17. key1 = null;
  18. // 内存回收,这里会回收WeakHashMap中与"key0"对应的键值对
  19. System.gc();
  20. try {
  21.     Thread.sleep(100);
  22. } catch (InterruptedException e) {
  23.     e.printStackTrace();
  24. }
  25. // 遍历WeakHashMap
  26. for (Map.Entry < String, String > m: weakHashMap.entrySet()) {
  27.     System.out.printf("next : %s >>> %s\n", m.getKey(), m.getValue());
  28. }
  29. // 打印WeakHashMap的实际大小
  30. System.out.printf("after gc WeakHashMap size: %s\n", weakHashMap.size());
复制代码
底层源码

构造器

[code]// 默认构造函数。WeakHashMap()// 指定“容量大小”的构造函数WeakHashMap(int capacity)// 指定“容量大小”和“加载因子”的构造函数WeakHashMap(int capacity, float loadFactor)// 包含“子Map”的构造函数WeakHashMap(Map

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

来自云龙湖轮廓分明的月亮

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表