zoukankan      html  css  js  c++  java
  • 【Java】Java中的四种对象引用

    从JDK1.2开始,Java中的引用类型分为四种,分别是:

    1.强引用(StrongReference)
      这种引用是平时开发中最常用的,例如 String strong = new String("Strong Reference")当一个实例对象具有强引用时,垃圾回收器不会回收该对象,当内存不足时,宁愿抛出OutOfMemeryError异常也不会通过回收强引用的对象,因为JVM认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误。

    2.软引用(SoftRefernce)
      如果一个对象只有软引用,那么只有当内存不足时,JVM才会去回收该对象,其他情况不会回收。软引用可以结合ReferenceQueue来使用,当由于系统内存不足,导致软引用的对象被回收了,JVM会把这个软引用加入到与之相关联的ReferenceQueue中。
    ReferenceQueue referenceQueue = new ReferenceQueue();
    SoftReference<Book> softReference = new SoftReference<>(new Book(), referenceQueue);
    Book book = softReference.get();
    Reference reference = referenceQueue.poll();

    当系统内存不足时,触发gc,这个Book就会被回收,reference 将不为null。


    3.弱引用(WeakReference)
      只有弱引用的对象,当JVM触发gc时,就会回收该对象。与软引用不同的是,不管是否内存不足,弱引用都会被回收。弱引用可以结合ReferenceQueue来使用,当由于系统触发gc,导致软引用的对象被回收了,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中,不过由于垃圾收集器线程的优先级很低,所以弱引用不一定会被很快回收。下面通过一个主动触发gc的例子来验证此结论。

    ReferenceQueue referenceQueue = new ReferenceQueue();
    WeakReference<Book> weakReference = new WeakReference(new Book(), referenceQueue);
    Book book = softReference.get();
    System.gc();
    //Runtime.getRuntime().gc();
    Reference reference = referenceQueue.poll();

    当然这不是每次都能复现,因为我们调用System.gc()只是告诉JVM该回收垃圾了,但是它什么时候做还是不一定的,但就我测试来看,只要多写几次System.gc(),复现的概率还是很高的。

      PS,

      ThreadLocalMap中的静态内部类Entry类就是继承了WeakRefence<ThreadLocal>这个类在构造方法中

    static class ThreadLocalMap {
    
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                   //调用父类WeakReference的构造方法
                    super(k);
                    value = v;
                }
            }

      

    public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
               //ThreadLocalMap将ThreadLocal作为key,(注意这个Key有点特殊,这个Key被弱引用关联)
                map.set(this, value);
            else
                createMap(t, value);
        }
     private void set(ThreadLocal<?> key, Object value) {
    
                // We don't use a fast path as with get() because it is at
                // least as common to use set() to create new entries as
                // it is to replace existing ones, in which case, a fast
                // path would fail more often than not.
    
                Entry[] tab = table;
                int len = tab.length;
                int i = key.threadLocalHashCode & (len-1);
    
                for (Entry e = tab[i];
                     e != null;
                     e = tab[i = nextIndex(i, len)]) {
                    //e最终获取的是其实是被弱引用WeakRerference关联的ThreadLocal
                    ThreadLocal<?> k = e.get();
    
                    if (k == key) {
                        e.value = value;
                        return;
                    }
    
                    if (k == null) {
                        replaceStaleEntry(key, value, i);
                        return;
                    }
                }
    
                tab[i] = new Entry(key, value);
                int sz = ++size;
                if (!cleanSomeSlots(i, sz) && sz >= threshold)
                    rehash();
            }
    //Reference中的Get方法    
        public T get() {
            return this.referent;
        }

    注意:

      由于Thread 线程对象都具有成员变量ThreadLocal.ThreadLocalMap,

      而ThreadLocalMap中的key就是当前ThreadLocal对象,而value就是我们想要和线程上下文绑定的数据,

      同时ThreadLocal又被弱引用关联,

      因此在线程生命周期结束时,其成员变量ThreadLocal.ThreadLocalMap,也会为null,此时内部的Entry会做额外的操作将value置为null,

           这样就满足了弱引用被回收的条件:当且仅当Entry的key持有弱引用时,该ThreadLocal就会被回收,解决了ThreadLocal对象内存泄漏的问题;

    4.虚引用(PhantomReference)
      如果一个对象只有虚引用在引用它,垃圾回收器是可以在任意时候对其进行回收的,虚引用主要用来跟踪对象被垃圾回收器回收的活动,当被回收时,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中。与软引用和弱引用不同的是,虚引用必须有一个与之关联的ReferenceQueue,通过phantomReference.get()得到的值为null,试想一下,如果没有ReferenceQueue与之关联还有什么存在的价值呢?
     
    PhantomReference<Book> phantomReference = new PhantomReference<>(new Book(), referenceQueue);
    Book book = phantomReference.get(); //此值为null
    Reference reference = referenceQueue.poll();


     



  • 相关阅读:
    摩拜单车--获地球卫士奖
    项目经理--读书静心的日子
    20165219 Exp1 PC平台逆向破解
    2018-2019-2 20165219《网络对抗技术》Exp0 Kali安装 Week1
    2018-2019-1 20165219《信息安全系统设计基础》实验五
    ### 2018-2019-1 20165219《信息安全系统设计基础》实验四
    实现mypwd
    mybash的实现
    2018-2019-1 20165219 实验三 实时系统
    2018-2019-1 20165219 《信息安全系统设计基础》第七周学习总结
  • 原文地址:https://www.cnblogs.com/july-sunny/p/12602442.html
Copyright © 2011-2022 走看看