weakHashMap
包路径:package java.util;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
1、继承于AbstractMap,实现了Map接口。
2、weakHashMap是哈希表,但是它的键是“弱键”,weakHashMap中保护几个重要的成员变量:
table是一个Entry[ ]类型的数组,而Entry是一个单向链表,哈希表中的键值对都是存储在Entry数组中的。
size是表示保存的键值对的数量大小。
threshold是阈值,用于判断是否需要扩充容量。
loadFactor是加载因子。
modCount是用来实现fail-fast机制的。
queue保存的是“已被GC清除的”“弱引用的键”。
3、该集合类的主要特点是:
随着时间的推移,键值对会逐渐的减少----->GC 垃圾回收
基本原理:weakHashMap的特点是:当除了自身有对key的引用之外,此key没有其他的引用,那么weakHashMap会在下一次对weakHashMap进行增删改查操作的时候及时丢弃该键值对,节约内存的使用,此特性使得weakHashMap比较适合构建缓存系统。
weakHashMap主要是通过expungeStaleEntries函数来实现移除内部不用的Entry从而达到自动释放内部的目的。
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
通过循环一直从queue中取出过期的entry,直至取完为止
synchronized (queue) { 通过加锁进行删除操作
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
在同步代码块中先把queue中取出的Object类型的数据强制转化为Entry对象e,然后计算此entry在桶中的位置,然后开始遍历entry链表,如果此entry是链表头,设置此entry的后继为新的链表头
if (prev == e)
table[i] = next;
else
然后将此entry的前序节点的后继指针指向此entry的后继节点
prev.next = next;
设置被删除的entry的value为null,加速垃圾回收,相应的size--
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
4、弱键的原理------>大致是通过WeakReference和ReferenceQueue来实现的。
实现步骤:(1)创建weakHashMap的时候,将键值对存放到数组链表当中;(2)当发生GC时会判断key是否有对象引用,如果没有引用了,就回收该key,意味着我们的entry实体从我们的集合中回收,回收的同时,将该对象加入到ReferenceQueue中;(3)在操作weakHashMap的时候,会首先同步table和Queue,table存放的是所有有效的键值对,Queue存放的是被回收的键值对,在table中删除Queue中有的键值对。
5、关于Java中的4种引用
(WeakHashMap中使用WeakReference,也就是通过虚引用来实现的)
(1)强引用(Strong Reference)--->永远不会回收被引用的对象,比如代码中new出来的对象
(2)软引用(SoftReference)--->表示有用但是非必需的,如果系统内存资源紧张,可能就会被回收
(3)弱引用(WeakReference)--->表示非必需的对象,只能存活到下一次垃圾回收发生之前
(4)虚引用(PhantomReference)--->是最弱的,该引用无法操作对象
6、哪些方法会产生清理元素的操作?
put、get方法开始的getTable会调用一次expungeStaleEntries
resize方法开始的getTable会调用一次expungeStaleEntries
transfer方法本身会判断弱引用指向的对象是否已经被GC
扩容之后发现size小于阈值的一半,会调用一次expungeStaleEntries
size方法会调用expungeStaleEntries