WeakHashMap理解

作者: wiflish 分类: 技术 发布时间: 2014-05-09 22:10 ė 6没有评论

WeakHashMap是一个Map。WeakHashMap 继承于AbstractMap,实现了Map接口

WeakHashMap的键为弱键,当某个键不再正常使用时,会被从WeakHashMap中被自动移除。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。某个键被终止时,它对应的键值对也就从映射中有效地移除了。

其特征就是:将键和值放入WeakHashMap中后,过了某一个时间(系统多次gc后),WeakHashMap中的数据(包含键和值)就会被gc掉。

http://www.cnblogs.com/skywang12345/p/3311092.html

对WeakHashMap的理解:

概要

这一章,我们对WeakHashMap进行学习。
我们先对WeakHashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用WeakHashMap。
第1部分 WeakHashMap介绍
第2部分 WeakHashMap数据结构
第3部分 WeakHashMap源码解析(基于JDK1.6.0_45)
第4部分 WeakHashMap遍历方式
第5部分 WeakHashMap示例

转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311092

第1部分 WeakHashMap介绍

WeakHashMap简介

    WeakHashMap 继承于AbstractMap,实现了Map接口。
    和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null
   不过WeakHashMap的键是“弱键”。在 WeakHashMap 中,当某个键不再正常使用时,会被从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共有4个构造函数,如下:

复制代码
// 默认构造函数。
WeakHashMap()

// 指定“容量大小”的构造函数
WeakHashMap(int capacity)

// 指定“容量大小”和“加载因子”的构造函数
WeakHashMap(int capacity, float loadFactor)

// 包含“子Map”的构造函数
WeakHashMap(Map<? extends K, ? extends V> map)
复制代码

WeakHashMap的API

复制代码
void                   clear()
Object                 clone()
boolean                containsKey(Object key)
boolean                containsValue(Object value)
Set<Entry<K, V>>       entrySet()
V                      get(Object key)
boolean                isEmpty()
Set<K>                 keySet()
V                      put(K key, V value)
void                   putAll(Map<? extends K, ? extends V> map)
V                      remove(Object key)
int                    size()
Collection<V>          values()
复制代码

第2部分 WeakHashMap数据结构

WeakHashMap的继承关系如下

复制代码
java.lang.Object
   ↳     java.util.AbstractMap<K, V>
         ↳     java.util.WeakHashMap<K, V>

public class WeakHashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V> {}
复制代码

WeakHashMap与Map关系如下图:

从图中可以看出:
(01) WeakHashMap继承于AbstractMap,并且实现了Map接口。
(02) WeakHashMap是哈希表,但是它的键是”弱键”。WeakHashMap中保护几个重要的成员变量:tablesizethresholdloadFactormodCountqueue
  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的”key-value键值对”都是存储在Entry数组中的。 
  size是Hashtable的大小,它是Hashtable保存的键值对的数量。 
  threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值=”容量*加载因子”。
  loadFactor就是加载因子。 
  modCount是用来实现fail-fast机制的
  queue保存的是“已被GC清除”的“弱引用的键”。

第3部分 WeakHashMap源码解析(基于JDK1.6.0_45)

 下面对WeakHashMap的源码进行说明

 View Code

说明:WeakHashMap和HashMap都是通过”拉链法”实现的散列表。它们的源码绝大部分内容都一样,这里就只是对它们不同的部分就是说明。

    WeakReference是“弱键”实现的哈希表。它这个“弱键”的目的就是:实现对“键值对”的动态回收。当“弱键”不再被使用到时,GC会回收它,WeakReference也会将“弱键”对应的键值对删除。
    “弱键”是一个“弱引用(WeakReference)”,在Java中,WeakReference和ReferenceQueue 是联合使用的。在WeakHashMap中亦是如此:如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。 接着,WeakHashMap会根据“引用队列”,来删除“WeakHashMap中已被GC回收的‘弱键’对应的键值对”。
    另外,理解上面思想的重点是通过 expungeStaleEntries() 函数去理解。

第4部分 WeakHashMap遍历方式

4.1 遍历WeakHashMap的键值对

第一步:根据entrySet()获取WeakHashMap的“键值对”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

复制代码
// 假设map是WeakHashMap对象
// map中的key是String类型,value是Integer类型
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    // 获取key
    key = (String)entry.getKey();
        // 获取value
    integ = (Integer)entry.getValue();
}
复制代码

4.2 遍历WeakHashMap的键

第一步:根据keySet()获取WeakHashMap的“键”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

复制代码
// 假设map是WeakHashMap对象
// map中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)map.get(key);
}
复制代码

4.3 遍历WeakHashMap的值

第一步:根据value()获取WeakHashMap的“值”的集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

复制代码
// 假设map是WeakHashMap对象
// map中的key是String类型,value是Integer类型
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}
复制代码

WeakHashMap遍历测试程序如下

复制代码
  1 import java.util.Map;
  2 import java.util.Random;
  3 import java.util.Iterator;
  4 import java.util.WeakHashMap;
  5 import java.util.HashSet;
  6 import java.util.Map.Entry;
  7 import java.util.Collection;
  8 
  9 /*
 10  * @desc 遍历WeakHashMap的测试程序。
 11  *   (01) 通过entrySet()去遍历key、value,参考实现函数:
 12  *        iteratorHashMapByEntryset()
 13  *   (02) 通过keySet()去遍历key、value,参考实现函数:
 14  *        iteratorHashMapByKeyset()
 15  *   (03) 通过values()去遍历value,参考实现函数:
 16  *        iteratorHashMapJustValues()
 17  *
 18  * @author skywang
 19  */
 20 public class WeakHashMapIteratorTest {
 21 
 22     public static void main(String[] args) {
 23         int val = 0;
 24         String key = null;
 25         Integer value = null;
 26         Random r = new Random();
 27         WeakHashMap map = new WeakHashMap();
 28 
 29         for (int i=0; i<12; i++) {
 30             // 随机获取一个[0,100)之间的数字
 31             val = r.nextInt(100);
 32             
 33             key = String.valueOf(val);
 34             value = r.nextInt(5);
 35             // 添加到WeakHashMap中
 36             map.put(key, value);
 37             System.out.println(" key:"+key+" value:"+value);
 38         }
 39         // 通过entrySet()遍历WeakHashMap的key-value
 40         iteratorHashMapByEntryset(map) ;
 41         
 42         // 通过keySet()遍历WeakHashMap的key-value
 43         iteratorHashMapByKeyset(map) ;
 44         
 45         // 单单遍历WeakHashMap的value
 46         iteratorHashMapJustValues(map);        
 47     }
 48     
 49     /*
 50      * 通过entry set遍历WeakHashMap
 51      * 效率高!
 52      */
 53     private static void iteratorHashMapByEntryset(WeakHashMap map) {
 54         if (map == null)
 55             return ;
 56 
 57         System.out.println("\niterator WeakHashMap By entryset");
 58         String key = null;
 59         Integer integ = null;
 60         Iterator iter = map.entrySet().iterator();
 61         while(iter.hasNext()) {
 62             Map.Entry entry = (Map.Entry)iter.next();
 63             
 64             key = (String)entry.getKey();
 65             integ = (Integer)entry.getValue();
 66             System.out.println(key+" -- "+integ.intValue());
 67         }
 68     }
 69 
 70     /*
 71      * 通过keyset来遍历WeakHashMap
 72      * 效率低!
 73      */
 74     private static void iteratorHashMapByKeyset(WeakHashMap map) {
 75         if (map == null)
 76             return ;
 77 
 78         System.out.println("\niterator WeakHashMap By keyset");
 79         String key = null;
 80         Integer integ = null;
 81         Iterator iter = map.keySet().iterator();
 82         while (iter.hasNext()) {
 83             key = (String)iter.next();
 84             integ = (Integer)map.get(key);
 85             System.out.println(key+" -- "+integ.intValue());
 86         }
 87     }
 88     
 89 
 90     /*
 91      * 遍历WeakHashMap的values
 92      */
 93     private static void iteratorHashMapJustValues(WeakHashMap map) {
 94         if (map == null)
 95             return ;
 96         
 97         Collection c = map.values();
 98         Iterator iter= c.iterator();
 99         while (iter.hasNext()) {
100             System.out.println(iter.next());
101        }
102     }
103 }
复制代码

第5部分 WeakHashMap示例

下面通过实例来学习如何使用WeakHashMap

复制代码
 1 import java.util.Iterator;
 2 import java.util.Map;
 3 import java.util.WeakHashMap;
 4 import java.util.Date;
 5 import java.lang.ref.WeakReference;
 6 
 7 /**
 8  * @desc WeakHashMap测试程序
 9  *
10  * @author skywang
11  * @email kuiwu-wang@163.com
12  */
13 public class WeakHashMapTest {
14 
15     public static void main(String[] args) throws Exception {
16         testWeakHashMapAPIs();
17     }
18 
19     private static void testWeakHashMapAPIs() {
20         // 初始化3个“弱键”
21         String w1 = new String("one");
22         String w2 = new String("two");
23         String w3 = new String("three");
24         // 新建WeakHashMap
25         Map wmap = new WeakHashMap();
26 
27         // 添加键值对
28         wmap.put(w1, "w1");
29         wmap.put(w2, "w2");
30         wmap.put(w3, "w3");
31 
32         // 打印出wmap
33         System.out.printf("\nwmap:%s\n",wmap );
34 
35         // containsKey(Object key) :是否包含键key
36         System.out.printf("contains key two : %s\n",wmap.containsKey("two"));
37         System.out.printf("contains key five : %s\n",wmap.containsKey("five"));
38 
39         // containsValue(Object value) :是否包含值value
40         System.out.printf("contains value 0 : %s\n",wmap.containsValue(new Integer(0)));
41 
42         // remove(Object key) : 删除键key对应的键值对
43         wmap.remove("three");
44 
45         System.out.printf("wmap: %s\n",wmap );
46 
47 
48 
49         // ---- 测试 WeakHashMap 的自动回收特性 ----
50     
51         // 将w1设置null。
52         // 这意味着“弱键”w1再没有被其它对象引用,调用gc时会回收WeakHashMap中与“w1”对应的键值对
53         w1 = null;
54         // 内存回收。这里,会回收WeakHashMap中与“w1”对应的键值对
55         System.gc();
56 
57         // 遍历WeakHashMap
58         Iterator iter = wmap.entrySet().iterator();
59         while (iter.hasNext()) {
60             Map.Entry en = (Map.Entry)iter.next();
61             System.out.printf("next : %s - %s\n",en.getKey(),en.getValue());
62         }
63         // 打印WeakHashMap的实际大小
64         System.out.printf(" after gc WeakHashMap size:%s\n", wmap.size());
65     }
66 }
复制代码

运行结果

复制代码
wmap:{three=w3, one=w1, two=w2}
contains key two : true
contains key five : false
contains value 0 : false
wmap: {one=w1, two=w2}
next : two - w2
 after gc WeakHashMap size:1
复制代码

 

 

本文出自 Wiflish's Blog,转载时请注明出处及相应链接。

本文永久链接: http://wiflish.fyard.com/archives/84

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Ɣ回顶部