介绍
单例模式是Java中最简单的设计模式之一,这种类型的设计模式属于创建型模式,涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象
几种实现方式
懒汉式,延迟加载,线程不安全
这种方式是最基本的实现方式,存在的问题是不支持多线程,所以严格意义上也不能算单例模式。延迟加载,不要求线程安全,在多线程不能正常工作
public class Singleton {
private static Singleton instance;
//让构造函数为 private,这样该类就不会被实例化
private Singleton (){}
public static Singleton getInstance() {
//延迟加载
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
接下来几种实现方式都支持多线程,但是性能上有所差异
懒汉式,延迟加载,线程安全
这种方式同样支持延迟加载,能在多线程中工作,但是相对效率低,因为每次获取实例时都需要进行同步
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式,不延迟加载,线程安全
这种方式比较常用,但容易产生垃圾对象,因为它虽然基于classLoader(类加载)机制避免了多线程的同步问题,但instance在类装载时就实例化,也不能确定还会有其他的方式导致类装载,这时候初始化instance很明显没有实现延迟加载
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
双重校验锁(DCL),延迟加载,线程安全
这种方式采用双锁机制,安全且在多线程情况下能保持高性能,不过Java5及以上版本才支持。这种机制并不是每次进入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意思是,被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量
登记式(静态内部类),延迟加载,线程安全
这种方式同样利用了classLoader机制来保证初始化instance时只有一个线程,但与饿汉式方式不同的是,饿汉式只要Singleton类被装载了,那么instance就会被实例化,没有达到延迟加载的效果。而这种方式当Singleton类被装载了,instance不一定被初始化,因为SingletonHolder类没有被主动使用,只有通过调用getInstance方法时,才会装载SingletonHolder类,从而实例化instance
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
枚举,不延迟加载,线程安全
这种实现方式还没有被广泛使用,但这是实现单例模式的最佳方式。它更加简洁,不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过Java5之后才加入枚举特性
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
本文仅仅介绍了单例模式及其实现方式,推荐学习【创建型模式四】单例模式(Singleton),写的很深入详细
参考:单例模式