引言
单例模式(Singleton Pattern)是属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
应用场景
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
- 为了保证资源不被浪费,所以使用单例创建一次对象,然后后面就可以不用创建对象了。
优缺点
- 优点:在内存中只有一个对象,节省内存空间。避免频繁的创建销毁对象,可以提高性能。避免对共享资源的多重占用。可以全局访问。
- 缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
Java 代码
饿汉
在虚拟机加载该类时就直接完成变量的初始化,没有线程安全问题,但是没有懒加载。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return instance;
}
}
懒汉
懒加载,线程不安全,可能多线程同时调用getInstance方法导致一个线程维护一个Singleton实例
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程安全
synchronized
在JDK1.6之前是重量级锁,涉及到系统调用,所以性能较差,但是在JDK1.6之后有优化(CAS + AQS),所以性能会好点。
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
静态内部
通过静态内部类持有一个实例,实现线程安全和饿汉原理一样,不过因为静态内部类使用到才加载,所以起到了延迟加载的作用。
public class Singleton {
private Singleton() {
}
private static Singleton instance;
public static synchronized Singleton getInstance() {
return SingletonHolder.instance;
}
static private class SingletonHolder{
private static final Singleton instance = new Singleton();
}
}
枚举
线程安全速度快,但是可读性较差。
public enum Singleton {
INSTANCE;
public void otherMethod() { }
}
双重检查
public class Singleton {
private Singleton() {
}
private volatile static Singleton instance;
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}