Java基础知识复习

学习目标

复习Java基础知识

  1. Java中有哪几种引用?它们的含义和区别是什么?
  2. 请用Java实现一个线程安全且高效的单例模式。

Java中有哪几种引用?它们的含义和区别是什么?

Java中有哪几种引用:

  • 强应用(StrongReference)

    强引用在程序之间普遍存在的,类似于Object obj = new Object()这类引用。只要强引用还存在,垃圾回收器就永远不会回收持被强引用关联的对象,如果想中断强引用和某个对象之间的关系,可以将引用赋值为null。

  • 软引用(SoftReference)

    软引用用来描述一些还有用,单并非必须的对象,对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围之中进行回收,如果此次回收还没有足够的内存,才会抛出内存溢出异常。

    String str = new String("abc");//强引用
    SoftReference<String> strRef = new SoftReference<String>(str);//软引用
    

    当内存不足时,等价于:

    if(JVM.内存不足){
        str = null;//转换为软引用
        System.gc();//垃圾回收器进行回收
    }
    
  • 弱引用(WeakReference)

    弱引用也是用来描述非必须对象的,它的强度比软引用还要弱一些,被弱引用关联的对象,只能生存到下一次垃圾回收之前,当垃圾回收器工作时,无论当前内存是否足够,都会回收只被弱引用关联的对象。

    String str = new String("str");
    WeakReference<String> weakRef = new WeakReference<String>(str);
    

    当垃圾回收器扫描回收时等价于:

    str = null;
    System.gc();
    
  • 虚引用(PhantomReference)

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

    虚引用主要用来跟踪对象被垃圾回收器回收的活动,虚引用与软引用和弱引用的一个区别在于,虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象的时候,如果发现它还有虚引用,就会在回收这个对象之前,把这个虚引用加入到与之关联的引用队列中。

请用Java实现一个线程安全且高效的单例模式

  1. 利用类加载机制来保证只创建一个instance实例,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。

    但是有两点需要注意:

    • 可能有人利用反射强制调用我们的私有构造器
    • 都需要额外的Serializable、transient、readResolve()来实现序列化,否则每次反序列化一个序列化实例都会创建一个新的实例。

      public class Singleton{
          private Singleton(){}
      
          public static Singleton getInstance(){
              return SingletonHolder.sInstance;
          }
      
          /**静态内部类*/
          public static class SingletonHolder{
              private final Singleton sInstance = new Singleton();
          }
      }  
      
  1. 使用DCL,保证序列化和反序列化安全,延迟加载,线程安全,防反射

    public    class MySingleton implements Serializable{
        private static final long serialVersionUID = 234234141414L;
        private static volatile MySingleton singleton;
        private static boolean isFirst = true;
        private MySingleton(){
            if(isFirst){
                isFirst = false;
            }else{
                throw new RuntimeException("破坏了单例,第二个实例创建失败");
            }
        }
    
        public static MySingleton getInstance(){
            if(sigleton == null){
                synchronized(MySingleton.class){
                    if(single == null){
                        singleton = new MySingleton();
                    }
                }
            }
            return singleton;
        }
    
        private Object readResolved(){
            return singleton;
        }
    }