平时我们使用最多的数据结构肯定是 HashMap,但是在使用的时候我们必须知道每个键值对的生命周期,并且手动清除它;但是如果我们不是很清楚它的生命周期,这时候就比较麻烦;通常有这样几种处理方式:
- 由一个线程定时处理,可以是
Timer或者ScheduledThreadPoolExecutor; - 利用重写
LinkedHashMap.removeEldestEntry(),实现 FIFOCache 或者 LRUCache;可以参考我之前写的一篇博客 LinkedHashMap 相关;https://www.cnblogs.com/sanzao/p/10367123.html - 利用
WeakHashMap的特性,如果逻辑比较复杂还可以直接使用Reference;这里可以参考 Reference 完全解读 和 Reference 框架概览;
所以本文将主要介绍WeakHashMap的特性,以及补充一些关于 HashMap 实现的对比;相关 HashMap 的介绍也可以参考 HashMap 相关;
一、使用场景
上面也介绍了,WeakHashMap适用于不是非常重要的缓存类似的场景;例如:
WeakHashMap<Object, Integer> map = new WeakHashMap<>(); for (int i = 0; i < 100; i++) { map.put(new Object(), i); } System.out.println(map.size()); // 1 System.gc(); // 2 System.out.println(map.size()); // 3 System.out.println(map.size()); // 4 System.out.println(map.size()); // 5 System.out.println(map); // 6 System.out.println(map.size()); // 7// 打印:
100
100
100
46
{}
0
对于以上的结果你可能和我打印的不一样,WeakHashMap按照语义应该是,当 key 没有强引用指向的时候,会自动清除 key 和 value;我这里先解释它的释放过程,如果你觉得很清晰,那WeakHashMap你就算是掌握了;
- 首先 for 循环结束的时候,key 已经没用强引用指向了,此时所有的 key 都是弱引用了;
- 接下来执行1,因为我这里只有一个方法,新生代还有足够的空间,所以不会触发 GC,所以所有的 key 任然在堆里面,所以打印100;
- 然后手动触发 GC,虽然
System.gc();不一定会立即执行,但是我这里只有一个方法,所以肯定会执行 GC,这里可以打开 GC 日志查看,-verbose:gc;因为 所有的 key 都是弱引用,所以referent被致为 null,同时将 key 注册到ReferenceQueue中; - 在执行 3-7 的时候,按语义 map 应该为空;但是将 key 注册到
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率
