zoukankan      html  css  js  c++  java
  • Java引用类型

      强软弱虚 四种引用类型

      1.Java中默认的就是强引用

    public class T {
    
        /**
         * java垃圾回收时会调用一次且只调用一次
         * @throws Throwable
         */
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("finalize执行....");
        }
    }
    *********************************
    public class StrongReferenceTest {
        public static void main(String[] args) {
            T t = new T();
            System.gc();
            System.out.println(t);
            t= null;
            System.gc();
            System.out.println(t);
        }
    }
    结果:

    com.example.reference.T@30946e09
    null
    finalize执行....

    Process finished with exit code 0

       强应用,那么如果对象有指向,垃圾回收器将不会回收它。

      手动置t为null的话GC回收就会回收该对象

      正常情况下,在方法内部有一个强引用,这个引用保存在栈中,而真正的应用内容T保存在堆中,当方法运行结束,就会退出方法栈,引用的变量t就会为null,这个对象就会被回收

      但是当为全局变量时,那就不会被回收了。

      例如ArrayList的clear()方法,是将每个elementData[i] == null 而非  elementData 对象置为null

      

      2.软引用(SoftReference)

    /**
    * -Xmx30M
    */
    public class SoftReferenceTest {
    public static void main(String[] args) {
    ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
    SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024*1024*10],referenceQueue);
    System.out.println(softReference.get()+"---"+softReference);
    System.gc();
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(softReference.get()+"---"+softReference);
    byte[] bytes2 = new byte[1024*1024*10];
    System.out.println(softReference.get()+"---"+softReference);
    Reference<? extends byte[]> poll = referenceQueue.poll();
    System.out.println(poll);
    }
    }

      如果一个对象只具有软引用,则内存空间充足时,垃圾回收器不会回收它;如果内存空间不足了,就会回收这些对象的内存,只要垃圾回收器没有回收它,该对象就可以被程序使用

      软引用使用场景,做缓存使用。

      软引用可以把一个引用队列(ReferenceQueue)联合使用。如果软引用所引用对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中

    引用队列的作用:

      垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软引用对象,而且虚拟机会尽可能优先回收长时间闲置不用额软引用对象。

      对于哪些刚构建的或刚使用过的“较新”软对象会被虚拟机尽可能保留,所以引入引用队列ReferenceQueue的原因

    [B@4459eb14---java.lang.ref.SoftReference@5a2e4553
    [B@4459eb14---java.lang.ref.SoftReference@5a2e4553
    null---java.lang.ref.SoftReference@5a2e4553
    java.lang.ref.SoftReference@5a2e4553
    

      

     通过结果我们可以分析出,

      本身softReference连接SoftReference是强引用(第三行,softReference对象有值,)

      SoftReference连接byte[] 是软引用,内存不够后,gc回收(第三行,softReference.get() 结果为null

    垃圾回收也只清除软引用的连接,清除不了强引用

      3.弱引用(WeakReference)

      弱引用与软引用的区别在于,只具有软引用的对象拥有更短暂的生命周期。

      在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存是否足够,都会回收内存。

    public class WeakReferenceTest {
        public static void main(String[] args) {
    //        WeakReference<T> weak = new WeakReference(new T());
            WeakReference<String> weak = new WeakReference(new String("abc"));
            System.out.println(weak.get() + "---" + weak);
            System.gc();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(weak.get() + "---" + weak);
            System.out.println("***************************");
            System.out.println(weak.get() + "---" + weak);
        }
    }

    abc---java.lang.ref.WeakReference@4459eb14
    null---java.lang.ref.WeakReference@4459eb14
    ***************************
    null---java.lang.ref.WeakReference@4459eb14

      第一次打印出来,第二次打印之前调用gc,所以会打印null值,

      weak指向WeakReference弱引用对象,弱引用对象指向new String()对象,gc会把后者的关系给回收。

    实际使用场景ThreadLocal 

      

    package com.example.reference;
    
    public class ThreaLocalTest {
        private static ThreadLocal<String> threadLocal= new ThreadLocal<>();
        public static void main(String[] args) throws Exception {
            new Thread(()->{
                    threadLocal.set(Thread.currentThread().getName()+"-----哈哈");
                    System.out.println("线程1"+threadLocal.get());
            }).start();
            new Thread(()->{
                    System.out.println("线程2"+threadLocal.get());
            }).start();
            Thread.sleep(500);
            System.in.read();
        }
    }
    结果:
    线程1Thread-0-----哈哈
    线程2null
    

      说明第一个线程的set值干扰不到第二个线程的数据正确性

    源码分析:

      

     set方法第一步获取当前线程,然后拿到ThreadLocalMap对象是一个key-value结构,key为this也就是ThreadLocal对象,所以最为关键的是ThreadLocalMap对象如何获取

      

     threadLocalMap对象是Thread类的一个属性,所以说天然不同线程互不干扰

       分析createMap发现内部new Entry()对象这个对象继承WeakReference 把key放置其中

      ThreadLocal关系图如上:

      在线程Thread中 定义一个变量 t1 强引用new一个对象ThreadLocal

        t1.set()会在Thread内部构建一个ThreadLocalMap对象用于存储信息

        存储的信息又是构建成一个Entry对象,而entry对象又是继承弱引用对象

        t1通过强引用指向ThreadLocal对象,而Map里面的key又是通过弱引用指向ThreadLocal对象。

          如果map里面的引用是强引用,那么就是t1使用结束后,退出栈后但是map里面仍然使用强引用关联导致ThreadLocal这个对象始终无法回收,缓存弱引用的话,只要一gc就回收

        假设t1的指向被回收,key指向也被回收,key指向一个null,但是这个map仍然存在,里面的value一直存在,且会一直变大。仍然最后导致内存泄漏。

          所以ThreadLocal提供了remove方法在方法使用后进行调用

      4.虚引用(PhantomReference) 

      虚引用顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收

      虚引用必须和引用队列联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中

      虚引用用来管理对外内存,而我们的gc回收的永远是jvm的内存触发不了堆外内存,如果使用虚引用可以以一种别的方式进行内存回收

    public class PhantomReferenceTest {
        public static void main(String[] args) {
            ReferenceQueue queue = new ReferenceQueue();
            PhantomReference<T> reference = new PhantomReference<>(new T(),queue);
            System.out.println(reference.get()+"----"+reference);
            Reference poll = queue.poll();
            System.out.println(poll.get());
        }
    }
    null----java.lang.ref.PhantomReference@4459eb14
    Exception in thread "main" java.lang.NullPointerException
    	at com.example.reference.PhantomReferenceTest.main(PhantomReferenceTest.java:13)
    

      

     

     

     

     

     

     

     

     https://blog.csdn.net/baidu_22254181/article/details/82555485

     

  • 相关阅读:
    【sqlite】python备份数据库
    【elasticsearch】python下的使用
    Raft
    SQL注入攻击和防御
    The world beyond batch: Streaming 101
    MillWheel: Fault-Tolerant Stream Processing at Internet Scale
    Flink DataSet API Programming Guide
    The Dataflow Model 论文
    让Storm插上CEP的翅膀
    Siddhi CEP Window机制
  • 原文地址:https://www.cnblogs.com/huan30/p/12790411.html
Copyright © 2011-2022 走看看