开始
设计模式(Design pattern),提供了在软件开发过程中面临的一些问题的最佳解决方案,是Java开发者必修的一门课程。主要分创建型模式、结构型模式和行为型模式。其中接下来我们要讨论的是单例模式,属于创建型模式。
单例模式,说白了就是类只有一个实例,这个类提供了一个访问其唯一的对象的方式,可以直接访问,不需要进行实例化该类的对象。说到了单例模式,就不得不提“static”这个关键字了,没有它单例模式就不能实现。如果你对“static关键字”有兴趣,可以看移步Java中的static关键字
实现单例模式有很多种,每种方法各有利弊,下面我们来看下有哪几种实现方式吧:
前提
要想玩单例模式,第一件不能忘了的事就是“构造方法私有化”,说白了就是用“private”替换“public”来修饰构造方法,让这个类不能通过“new”的方式来进行实例。
单例 - 饿汉模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
这种方式之所以成为饿汉模式,就是指全局的单例实例在类装载时构建,所以类加载较慢,但获取对象实例的速度快(注:这里的快与慢是相对来讲的)。
单例 - 懒汉模式(线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种实现方式是最基础的实现方式,线程上下文单例,不需要共享给所有线程,也不需要加“synchronize”之类的锁,懒汉模式中同样声明一个静态对象,在用户第一次调用时初始化,加载时需要实例化,相对稍微会慢一些,而且在多线程下不能正常工作。
单例 - 懒汉模式(线程安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种懒汉模式很明显,我们多用了一个“synchronized”来修饰获取类实例的静态方法,这种写法保证线程安全,相对性能很低,而且大部分情况下我们是用不到同步的,所以不建议用这种模式。
单例 - 双检锁式
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return singleton;
}
}
双检锁式是在懒汉式基础上利用“synchronize”关键字和“volatile”关键字确保第一次创建时没有线程间竞争而产生多个实例,仅第一次创建时同步,性能相对较高。
单例 - 枚举单例
public enum Singleton {
instance;
...
...
...
}
我们还可以用Java中的枚举,因为Java中枚举类本身也是一种单例模式,枚举实例的创建是线程安全的,并且在任何情况下都是单例。枚举单例很简单,但是大部分应用开发很少用枚举,可读性并不是很高,不建议用。
总结
至此我总结了大概有5种方式可以用来创建单例模式,其实在我们的开发过程中并不是只有这5种。包括还可以通过静态内部类来创建单例模式,通过容器(HashMap)也可以,等等。
显然单例模式的要点有三个:
- 一是某个类只能有一个实例。
- 二是它必须自行创建这个实例。
- 三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下三点:
- 一是单例模式的类只提供私有的构造函数。
- 二是类定义中含有一个该类的静态私有对象。
- 三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。