第八周 Java基础知识学习(引用,单例)

话题:Java基础知识学习

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

  1. 强引用

只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象

Obejct obj = new Object();
obj = null;//强行中断引用可以赋值为Null
  1. 软引用(SoftReference)

有用但是不必须对象 , 只有在内存不足的时候JVM才会回收该对象

Object obj = new Object();
SoftReference sr = new SoftReference<>(obj);
Object obj2 = sr .get();
 
 
  1. 弱引用(WeakReference)

当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象

Object obj = new Object();
WeakReference wr= new WeakReference<>(obj);
wr.get();
 
 
  1. 虚引用(PhantomReference)

虚引用不会决定对象的生命周期,如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解
被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

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

1.静态内部类

public class A {
    public A(){
    }
    public A getInstance(){
        return B.sInstance;
    }
    private static class B{
        private static final A sInstance = new A();
    }
}

利用类加载机制来保证只创建一个Instance实例,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会去创建单例对象

不安全的地方:
(1) 可以被反射强行调用私有构造器
(2) 需要额外的工作来实现序列化,否则反序列化的时候,都会创建新的实例

静态内部类实现线程安全的原因:

  1. 内部类加载时机是在类被调用的时候,也就是A.getInstance(),B才会加载,属于延迟加载
  2. static 对象具有唯一性,只会在类加载的时候初始化一次

2.双重锁定检查(DCL)

public class A implements Serializable {
    private A(){
    }

    private static  volatile A sInstance ;

    public static A getInstance(){
            if (sInstance   != null){
                synchronized (A.this){
                    if (sInstance   != null){
                        sInstance   = new A();
                    }
                }
            }
        return sInstance;
    }

   //序列化安全
    private Object readResolve(){
        return sInstance;
    }
}

防止序列化,消除指令重排对单例的影响

你可能感兴趣的:(第八周 Java基础知识学习(引用,单例))