Java中的WeakHashMap实现分析
2016-05-11 23:38
393 查看
在Java集合中有一种特殊的Map类型:WeakHashMap。 WeakHashMap 继承于AbstractMap,实现了Map接口。 和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null。 不过WeakHashMap的键是“弱键”,里面存放了键对象的弱引用,当某个键不再正常使用时,会从WeakHashMap中被自动移除。当一个键对象被垃圾回收,那么相应的值对象的引用会从Map中删除。WeakHashMap能够节约存储空间,可用来缓存那些非必须存在的数据。
那么这个“弱键”的原理呢?大致上是通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。实现步骤是: (01) 新建WeakHashMap,将“键值对”添加到WeakHashMap中。实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。 (02) 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。 (03) 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。 这就是“弱键”如何被自动从WeakHashMap中删除的步骤了。 和HashMap一样,WeakHashMap是不同步的。可以使用 Collections.synchronizedMap 方法来构造同步的 WeakHashMap。
WeakHashMap源码分析,WeakHashMap维护了一个ReferenceQueue,保存了所有存在引用的Key对象。WeakHashMap.Entry
WeakHashMap中有一个私有的expungeStaleEntries()方法,会在大部分共有方法中被调用。这个方法会将ReferenceQueue中所有失效的引用从Map中去除。
需要注意,WeakHashMap的Key是弱引用,Value不是。WeakHashMap不会自动释放失效的弱引用,仅当包含了expungeStaleEntries()的共有方法被调用的时候才会释放。
一个简单的例子:
运行结果(一直循环当中):
Map Size:3 1
2
3
Map Size:2
null
2
3
根据String的特性,
元素“1”的key已经没有地方引用了,所以进行了回收。
元素“2”是被放在常量池中的,所以没有被回收。
元素“3”因为还有变量s的引用,所以也没有进行回收。
原文地址:http://www.dexcoder.com/selfly/article/289
那么这个“弱键”的原理呢?大致上是通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。实现步骤是: (01) 新建WeakHashMap,将“键值对”添加到WeakHashMap中。实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。 (02) 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。 (03) 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。 这就是“弱键”如何被自动从WeakHashMap中删除的步骤了。 和HashMap一样,WeakHashMap是不同步的。可以使用 Collections.synchronizedMap 方法来构造同步的 WeakHashMap。
WeakHashMap源码分析,WeakHashMap维护了一个ReferenceQueue,保存了所有存在引用的Key对象。WeakHashMap.Entry
1.private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
1.// Entry是单向链表。 2.// 它是 “WeakHashMap链式存储法”对应的链表。 3.// 它实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), 4.// equals(Object o), hashCode()这些函数 5.private static class Entry<K, V> extends WeakReference<K> implements 6. Map.Entry<K, V> { 7. private V value; 8. private final int hash; 9. // 指向下一个节点 10. private Entry<K, V> next; 11. // 构造函数。 12. Entry(K key, V value, ReferenceQueue<K> queue, int hash, 13. Entry<K, V> next) { 14. super(key, queue); 15. this.value = value; 16. this.hash = hash; 17. this.next = next; 18. } 19. ... 20.}
WeakHashMap中有一个私有的expungeStaleEntries()方法,会在大部分共有方法中被调用。这个方法会将ReferenceQueue中所有失效的引用从Map中去除。
1.// 清空table中无用键值对。原理如下: 2.// (01) 当WeakHashMap中某个“弱引用的key”由于没有再被引用而被GC收回时, 3.// 被回收的“该弱引用key”也被会被添加到"ReferenceQueue(queue)"中。 4.// (02) 当我们执行expungeStaleEntries时, 5.// 就遍历"ReferenceQueue(queue)"中的所有key 6.// 然后就在“WeakReference的table”中删除与“ReferenceQueue(queue)中key”对应的键值对 7.private void expungeStaleEntries() { 8. Entry<K, V> e; 9. while ((e = (Entry<K, V>) queue.poll()) != null) { 10. int h = e.hash; 11. int i = indexFor(h, table.length); 12. Entry<K, V> prev = table[i]; 13. Entry<K, V> p = prev; 14. while (p != null) { 15. Entry<K, V> next = p.next; 16. if (p == e) { 17. if (prev == e) 18. table[i] = next; 19. else 20. prev.next = next; 21. e.next = null; // Help GC 22. e.value = null; // " " 23. size--; 24. break; 25. } 26. prev = p; 27. p = next; 28. } 29. } 30.}
需要注意,WeakHashMap的Key是弱引用,Value不是。WeakHashMap不会自动释放失效的弱引用,仅当包含了expungeStaleEntries()的共有方法被调用的时候才会释放。
一个简单的例子:
1.public static void main(String args[]) { 2. WeakHashMap<String, String> map = new WeakHashMap<String, String>(); 3. map.put(new String("1"), "1"); 4. map.put("2", "2"); 5. String s = new String("3"); 6. map.put(s, "3"); 7. while (map.size() > 0) { 8. try { 9. Thread.sleep(500); 10. } catch (InterruptedException ignored) { 11. } 12. System.out.println("Map Size:" + map.size()); 13. System.out.println(map.get("1")); 14. System.out.println(map.get("2")); 15. System.out.println(map.get("3")); 16. System.gc(); 17. } 18.}
运行结果(一直循环当中):
Map Size:3 1
2
3
Map Size:2
null
2
3
根据String的特性,
元素“1”的key已经没有地方引用了,所以进行了回收。
元素“2”是被放在常量池中的,所以没有被回收。
元素“3”因为还有变量s的引用,所以也没有进行回收。
原文地址:http://www.dexcoder.com/selfly/article/289
相关文章推荐
- SpringMVC实现文件上传
- RMQ算法
- java数据类型值的注意的地方
- SpringMVC处理Form表单
- 国际化java.util.MissingResourceException: Can't find bundle for base name message报错
- 关于eclipse代码提示的配置
- javamail邮箱发送
- JDK配置
- java序列化机制(一)
- java学习笔记(2):获取文件名和自定义文件过滤器
- jdk动态代理实现总结和范例
- 【Java】常见的Set类型,HashSet、TreeSet、LinkedHashSet
- java 死锁两种实现
- Java反射总结(二)
- 笔记Java基础
- java WEB 表单 验证码问题与解决
- Spring学习之路(一)—环境配置
- orm.hibernate3.HibernateSystemException: Unknown entity: java.util.ArrayList;
- Spring注入:配置与注解
- java的四种引用,强弱软虚,用到的场景