转载请注明源出处:http://www.cnblogs.com/lighten/p/7423818.html
1.前言
本章介绍一下WeakHashMap,这个类也很重要。要想明白此类的作用,先要明白Java定义的四种引用类型。传送门。这里简单概括一下这四种引用:
1.强引用:一般new出来的对象都属于强引用,只要该引用不是JVM回收机制回收的对象,就不会被清理。
2.软引用:使用SoftReference包装的强引用对象是软引用。在JVM内存存够的情况下,软引用的对象不会被回收,JVM将抛出OOM异常的时候,会按没有被使用的时间顺序回收软引用对象。也就是说SoftReference这个对象持有强引用不会对JVM造成干扰,JVM会判断该对象有没有被SoftReference对象以外的对象持有来判断其属于强引用还是软引用,只有SoftReference持有该对象引用时,该对象才是一个软引用。所以使用SoftReference.get方法可能获得强引用对象,也可能是null。这里要注意的是,SoftReference对象本身也是一个强引用对象,如果其持有的强引用被回收了,这个对象也没有存在的意义了,所以这个是需要我们进行清理的。在其构造方法中提供了一个ReferenceQueue对象,在SoftReference持有对象被回收了后,会自动加入这个queue,之后通过queue中有没有这个对象,清理掉这个引用就可以了。
3.弱引用:和软引用基本一致,不过其使用的是类WeakReference进行包装,而且JVM进行回收时就会回收掉该对象。其它的要点基本一致。
4.虚引用:使用PhantomReference进行包装,其与软引用和弱引用的机制不一样。其不会获得所持有对象,直接返回的就是null,只有在对象被回收才会被加入队列中。
根据这种中引用的特性,如何利用就仁者见仁智者见智了。
2.WeakHashMap
这个Map的特点就是其键是虚引用,当垃圾回收器触发时,并不会阻止键被回收。意味着键值对会自动移除,当键不再被正常使用的时候。空的key和value都是被允许的,整个和HashMap比较像,非同步类。实际上JDK8的WeakHashMap并没有像HashMap那么复杂,实现还是十分简单的,就是一个hash表,处理冲突就是使用了链表。
数据结构就是一个普通的table,还有就是hashmap中见到的threshold和loadfactor了。queue就是WeakHashMap虚引用的特有对象。
get方法就是先处理key为Null的情况,再计算在table中的下标,这个链表遍历,找到引用相等或引用相等的键,返回其值。这里面要注意的就是getTable方法,其实际上就是对table进行了清理。
当一个键没有被使用的时候,就会被GC回收,回收后就会进入queue中,getTable就是预先对表中废弃的键进行了清理。
put方法也是先对表中废弃的键进行清理,然后找到其位置,存在就替换旧值,不存在就插入到链表首位。数量超过阈值就扩容hash表。
remove方法就不再进行介绍了,操作原理都是一样的。所有涉及对表的操作,都会进行getTable()清理没有再被使用的键。WeakHashMap就可以简单的实现自动销毁不需要的键值了。
其它的也没有什么描述的必要。
3.用例测试
@Test
public void testWeakHashMap() {
WeakHashMap<Object, String> whm = new WeakHashMap<>();
Object one = new Object();
Object two = new Object();
whm.put(one, "one");
whm.put(two, "two");
one = null;
System.out.println(whm.size());
System.gc();
System.out.println(whm.size());
System.out.println(whm.get(two));
}
上面这个测试代码在我这里允许多次出现了两个结果:
2,1,two
2,2,two
所以gc发生的时间和弱引用进入队列的时间以及WeakHashMap清理废弃键的时间都是不确定的。这个类的使用也就是将一些资源value与键的生命周期绑定。键结束了value也就会被清除。前提是要触发WeakHashMap的相关方法。