1. 前言
今天面试前,笔试中遇到写单例模式的试题,之前也参考一些优秀博主的博客写过一遍。
在此,再次整理一下。
2. 单例模式要点
实现单例模式有以下三个要点:
1)首先要确保全局只有一个类的实例:要保证这一点,至少类的构造器要私有化
2)单例的类只有自己创建自己:因为构造器私有了,但还要有一个实例,只能自己创建咯
3)单例类必须能够提供自己的唯一的实例给其他类:就要有一个公共的方法能返回该实例类的唯一实例
3. 单例类的实现
单例类的实现有以下6种(两种饿汉式,两种懒汉式,双重校验锁及静态内部类):
具体介绍及实现如下:
1)饿汉式——静态常量方式(线程安全)
该方式在类加载时就初始化,天然线程安全
实现代码如下(注意使用了static):
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getSingleton () {
return instance;
}
}
2)饿汉式——静态代码块方式(线程安全)
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getSingleton () {
return instance;
}
}
3)懒汉式(线程不安全)
第一次调用才初始化,实现了懒加载特性,多线程禁用
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getSingleton() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
4)懒汉式(线程安全)
方法加上同步锁,相较于3性能会有折损,但也还好
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getSingleton() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
5)双重校验锁(线程安全,效率高)
注意volatile的使用,保证了各线程对singleton静态实例域修改的可见性
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
6)静态内部类实现单例(线程安全,效率高)
这种情况下Singleton被装载了,instance不一定被初始化。
因为SingleHolder类没有被主动使用,只有通过显示调用getInstance方法时,才会显式装载SingleHolder类,从而实例化instance。
注意内部类SingleHolder要用static修饰,且其中静态变量INSTANCE必须是final的
public class Singleton {
private static class SingleHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static Singleton getSingleton() {
return SingleHolder.INSTANCE;
}
}