话题:Java基础知识学习
1、Java中有哪几种引用?它们的含义和区别是什么?
- 强引用
只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象
Obejct obj = new Object();
obj = null;//强行中断引用可以赋值为Null
- 软引用(SoftReference)
有用但是不必须对象 , 只有在内存不足的时候JVM才会回收该对象
Object obj = new Object();
SoftReference<Object> sr = new SoftReference<>(obj);
Object obj2 = sr .get();
- 弱引用(WeakReference)
当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象
Object obj = new Object();
WeakReference<Object> wr= new WeakReference<>(obj);
wr.get();
- 虚引用(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) 需要额外的工作来实现序列化,否则反序列化的时候,都会创建新的实例
静态内部类实现线程安全的原因:
- 内部类加载时机是在类被调用的时候,也就是A.getInstance(),B才会加载,属于延迟加载
- 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;
}
}
防止序列化,消除指令重排对单例的影响
网友评论