1. Map

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,那么有WeakHashSet吗? java collections包是没有直接提供WeakHashSet的。
我们可以通过Collections.newSetFromMap(Map map)方法可以将任何 Map包装成一个Set。源码如下:

  1. public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
  2. return new SetFromMap<>(map);
  3. }
  4. /**
  5. * @serial include
  6. */
  7. private static class SetFromMap<E> extends AbstractSet<E>
  8. implements Set<E>, Serializable
  9. {
  10. private final Map<E, Boolean> m; // The backing map
  11. private transient Set<E> s; // Its keySet
  12. SetFromMap(Map<E, Boolean> map) {
  13. if (!map.isEmpty())
  14. throw new IllegalArgumentException("Map is non-empty");
  15. m = map;
  16. s = map.keySet();
  17. }
  18. public void clear() { m.clear(); }
  19. public int size() { return m.size(); }
  20. public boolean isEmpty() { return m.isEmpty(); }
  21. public boolean contains(Object o) { return m.containsKey(o); }
  22. public boolean remove(Object o) { return m.remove(o) != null; }
  23. public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
  24. public Iterator<E> iterator() { return s.iterator(); }
  25. public Object[] toArray() { return s.toArray(); }
  26. public <T> T[] toArray(T[] a) { return s.toArray(a); }
  27. public String toString() { return s.toString(); }
  28. public int hashCode() { return s.hashCode(); }
  29. public boolean equals(Object o) { return o == this || s.equals(o); }
  30. public boolean containsAll(Collection<?> c) {return s.containsAll(c);}
  31. public boolean removeAll(Collection<?> c) {return s.removeAll(c);}
  32. public boolean retainAll(Collection<?> c) {return s.retainAll(c);}

就是对传入的map进行了简单的包装

2. Queue队列

ReferenceQueue

引用队列,在检测到适当的可到达性更改后,垃圾回收器将已注册的引用对象添加到该队列中
实现了一个队列的入队(enqueue)和出队(poll还有remove)操作,内部元素就是泛型的Reference,并且Queue的实现,是由Reference自身的链表结构( 单向循环链表 )所实现的。
ReferenceQueue名义上是一个队列,但实际内部并非有实际的存储结构,它的存储是依赖于内部节点之间的关系来表达。可以理解为queue是一个类似于链表的结构,这里的节点其实就是reference本身。可以理解为queue为一个链表的容器,其自己仅存储当前的head节点,而后面的节点由每个reference节点自己通过next来保持即可。

  • 属性
    head:始终保存当前队列中最新要被处理的节点,可以认为queue为一个后进先出的队列。当新的节点进入时,采取以下的逻辑:

    1. r.next = (head == null) ? r : head;
    2. head = r;

    然后,在获取的时候,采取相应的逻辑:

    1. Reference<? extends T> r = head;
    2. if (r != null) {
    3. head = (r.next == r) ?
    4. null :
    5. r.next; // Unchecked due to the next field having a raw type in Reference
    6. r.queue = NULL;
    7. r.next = r;
  • 方法
    enqueue():待处理引用入队

    1. boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
    2. synchronized (lock) {
    3. // Check that since getting the lock this reference hasn't already been
    4. // enqueued (and even then removed)
    5. ReferenceQueue<?> queue = r.queue;
    6. if ((queue == NULL) || (queue == ENQUEUED)) {
    7. return false;
    8. }
    9. assert queue == this;
    10. r.queue = ENQUEUED;
    11. r.next = (head == null) ? r : head;
    12. head = r;
    13. queueLength++;
    14. if (r instanceof FinalReference) {
    15. sun.misc.VM.addFinalRefCount(1);
    16. }
    17. lock.notifyAll(); // ①
    18. return true;
    19. }
    20. }

    ① lock.notifyAll(); 👈通知外部程序之前阻塞在当前队列之上的情况。( 即之前一直没有拿到待处理的对象,如ReferenceQueue的remove()方法 )

参考

WeakHashMap的详细理解 https://blog.csdn.net/qiuhao9527/article/details/80775524 ReferenceQueue 详解 https://www.jianshu.com/p/f86d3a43eec5