面试官:请手写下几种常见的单例模式
我:好的(面带微笑),内心暗喜(送分题)。
没成想提笔便写出了如此豪放的代码,不堪回首,请原谅个人不羁!
java
实际编程应用场景中,有一些对象其实咱们只须要一个,好比线程池对象、缓存、系统全局配置对象等。这样能够就保证一个在全局使用的类不被频繁地建立与销毁,节省系统资源。面试
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
复制代码
类加载时就初始化实例,避免了多线程同步问题。自然线程安全。编程
其实就是在上面 静态常量饿汉式 实现上稍微变更了一下,将类的实例化放在了静态代码块中而已。其余没区别。缓存
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
复制代码
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
复制代码
这是最基本的实现方式,第一次调用才初始化,实现了懒加载的特性。多线程场景下禁止使用,由于可能会产生多个对象,再也不是单例。安全
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
复制代码
和上面 懒汉式(线程不安全)实现上惟一不一样是:获取实例的getInstance()方法上加了同步锁。保证了多线程场景下的单例。可是效率会有所折损,不过还好。多线程
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
复制代码
此种实现中不用每次须要得到锁,减小了获取锁和等待的事件。
注意volatile关键字的使用,保证了各线程对singleton静态实例域修改的可见性。spa
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
复制代码
这种方式下 Singleton 类被装载了,instance 不必定被初始化。由于 SingletonHolder 类没有被主动使用,只有经过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。
注意内部类SingletonHolder要用static修饰且其中的静态变量INSTANCE必须是final的。线程
此篇完。单例模式掌握至此,足以应付“手写单例”的面试场景。code