zoukankan      html  css  js  c++  java
  • WeakHashMap

    WeakHashMap

    今天在阅读《Effective Java》的【消除过期的对象引用】一章中,讲到了WeakHashMap,发现对该类不怎么熟悉,因此记录下整理的相关知识。

    Java的引用类型

    在学习WeakHashMap之前,得知道Java的4个引用类型:

    • 强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。比如String str = "hello"这时候str就是一个强引用。

    • 软引用:内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。

    • 弱引用:如果一个对象具有弱引用,在垃圾回收时候,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。

    • 虚引用:如果一个对象具有虚引用,就相当于没有引用,在任何时候都有可能被回收。使用虚引用的目的就是为了得知对象被GC的时机,所以可以利用虚引用来进行销毁前的一些操作,比如说资源释放等。

    而WeakHashMap的键就是弱引用,当某个键不再正常使用时,会被从WeakHashMap中被自动移除。

     

    WeakReference

    在WeakHashMap中真正实现弱引用的是WeakReference类,该类有两个构造方法:

    public class WeakReference<T> extends Reference<T> {
        public WeakReference(T referent) {
            super(referent);
        }
    ​
        public WeakReference(T referent, ReferenceQueue<? super T> q) {
            super(referent, q);
        }
    }
    • WeakReference(T referent):referent就是被弱引用的对象(注意区分弱引用对象和被弱引用的对应,弱引用对象是指WeakReference的实例或者其子类的实例),比如有一个Apple实例apple,可以如下使用,并且通过get()方法来获取apple引用。也可以再创建一个继承WeakReference的类来对Apple进行弱引用,下面就会使用这种方式。

    • WeakReference(T referent, ReferenceQueue<? super T> q):与上面的构造方法比较,多了个ReferenceQueue,在对象被回收后,会把弱引用对象,也就是WeakReference对象或者其子类的对象,放入队列ReferenceQueue中,注意不是被弱引用的对象,被弱引用的对象已经被回收了。

     

    WeakHashMap

    WeakHashMap的Entry继承了WeakReference,而后在构造方法中调用父类WeakReference的构造方法并将key设为被弱引用对象。

    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
            V value;
            final int hash;
            Entry<K,V> next;
    ​
            Entry(Object key, V value,
                  ReferenceQueue<Object> queue,
                  int hash, Entry<K,V> next) {
                super(key, queue);
                this.value = value;
                this.hash  = hash;
                this.next  = next;
            }
     }

    而在WeakHashMap内部有一个expungeStaleEntries函数,在这个函数内部实现移除其内部不用的entry从而达到的自动释放内存的目的。因此我们每次访问WeakHashMap的时候,都会调用这个expungeStaleEntries函数清理一遍。因为涉及到链表,所以下面代码讲解中将Entry称为链表中的一个节点。

    private void expungeStaleEntries() {
        //如果引用队列不为空,则说明有被弱引用的对象被GC回收,则需释放被弱引用的对象的Entry
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                Entry<K,V> e = (Entry<K,V>) x;
                //获取该entry在哈希表的数组索引
                int i = indexFor(e.hash, table.length);
                
                //获取哈希表i索引处的链表
                Entry<K,V> prev = table[i];
                //创建p指向当前节点,初始和前一个节点prev是同一个节点
                Entry<K,V> p = prev;
                while (p != null) {
                    //创建next节点指向当前节点p的下一个节点
                    Entry<K,V> next = p.next;
                    //如果当前节点等于被弱引用的对象的节点e,则需让当前节点失去引用,让e节点进入到下一波GC回收中
                    if (p == e) {
                    //如果前一个节点也等于被弱引用的对象的节点e,则说明当前节点p和前一个节点prev是同一个节点,
              //即需被弱引用的对象的节点e是table[i]处链表的头节点,则将table[i]设为下一节点,节点e失去引用
    if (prev == e) table[i] = next;           //反之,则说明被弱引用的对象的节点e是前一个节点prev的下一个节点,则将prev的下一个节点设为节点e的下一个节点,节点e失去引用 else prev.next = next; e.value = null; //将e的值设为null,加速垃圾回收 size--; break; } prev = p; p = next; } } } }



  • 相关阅读:
    AIX root用户密码丢失怎么办?
    Oracle 11g Grid Infrastructure 卸载
    Failed to create a peer profile for Oracle Cluster GPnP. gpnptool rc=32512
    管理 IBM AIX 中的用户
    vbox克隆文件的路径如何修改?默认它生成在C盘,怎么修改?
    Oracle_dataguard__11G_配置与维护手册
    AIX管理员常用命令
    如何让你的SQL运行得更快
    ORA00604: 递归 SQL 级别 1 出现错误,ORA01000: 超出打开游标的最大数
    Adobe Acrobat 9.0“ PDFMaker无法找到Adobe PDF Printer 的打印驱动程序”解决办法
  • 原文地址:https://www.cnblogs.com/gaofei200/p/14214049.html
Copyright © 2011-2022 走看看