一.简介
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。
二.为什么要用单例模式?
- 防止一个要全局使用的类频繁创建和销毁 ,节省内存,节省计算
- 防止多个实例造成结果混乱
- 方便管理,例如有些工具类我们只需要一个实例
三.要求
要求:只需要三部分即可保证只有一个实例
- 不允许被外部类 new 对象
- 在本类中创建对象
- 对外提供接口调用创建好的对象
四.实现思路
- 构造方法私有化
- 在本类中 new 一个本类对象
- 创建一个 public 方法返回上步创建好的对象以供外部调用
五.单例模式的码实现
一般来说,单例模式使用饿汉式实现就可以 饿汉式写法 和 静态内部类写法 就可以
懒汉: 要用时再去创建
饿汉: 类加载时化就去创建
5.1 懒汉式,线程不安全
* 是否 Lazy 初始化:是
* 是否多线程安全:否
* 优点:第一次调用才初始化,避免内存浪费。
* 描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
public class SingletonPattern {
//让构造函数为 private,这样该类就不会被实例化
private SingletonPattern() {
}
//创建 SingletonPattern 的一个对象
private static SingletonPattern instance;
//获取唯一可用的对象
public static SingletonPattern getInstance() {
if (instance == null) {
instance = new SingletonPattern();
}
return instance;
}
}
5.2 懒汉式,线程安全
* 是否 Lazy 初始化:是
* 是否多线程安全:是
* 描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
* 优点:第一次调用才初始化,避免内存浪费。
* 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。效率低
public class SingletonPattern {
//让构造函数为 private,这样该类就不会被实例化
private SingletonPattern() {
}
//创建 SingletonPattern 的一个对象,加上synchronized关键字,加上锁,保证单例,不过会影响效率,要是性能要求不高,就可以用这个方法
private static SingletonPattern instance;
//获取唯一可用的对象
public static synchronized SingletonPattern getInstance() {
if (instance == null) {
instance = new SingletonPattern();
}
return instance;
}
}
5.3 双检锁/双重校验锁(DCL,即 double-checked locking)
* JDK 版本:JDK1.5 起
* 是否 Lazy 初始化:是
* 是否多线程安全:是
* 效率高,线程安全
* 描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class SingletonPattern {
//加上volatile就是为了防止产生指令的重排序问题
private volatile static SingletonPattern singleton;
//让构造函数为 private,这样该类就不会被实例化
private SingletonPattern() {
}
//获取唯一可用的对象
public static SingletonPattern getSingleton() {
if (singleton == null) {//第一次检查
synchronized (SingletonPattern.class) {//加锁
if (singleton == null) {//第二次检查
singleton = new SingletonPattern();
}
}
}
return singleton;
}
}
5.4 静态内部类
* 是否 Lazy 初始化:是
* 是否多线程安全:是
* 描述:这种方式能达到双检锁方式一样的功效,但实现更简单。
* 线程安全
public class SingletonPattern {
//静态内部类
private static class SingletonHolder {
private static final SingletonPattern singletonPattern = new SingletonPattern();
}
//让构造函数为 private,这样该类就不会被实例化
private SingletonPattern (){}
//获取唯一可用的对象
public static final SingletonPattern getInstance() {
return SingletonHolder.singletonPattern;
}
}
5.5 枚举
* JDK 版本:JDK1.5 起
* 是否 Lazy 初始化:否
* 是否多线程安全:是
* 描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
public enum SingletonPattern {
INSTANCE;
public void whateverMethod() {
}
}
5.6 饿汉式,线程安全
* 是否 Lazy 初始化:否
* 是否多线程安全:是
* 描述:这种方式比较常用,但容易产生垃圾对象。
* 优点:没有加锁,执行效率会提高。线程安全
* 缺点:类加载时就初始化,浪费内存。
public class SingletonPattern {
//类加载时就完成了实例化SingletonPattern
private static SingletonPattern instance = new SingletonPattern();
//让构造函数为 private,这样该类就不会被实例化
private SingletonPattern (){}
//获取唯一可用的对象
public static SingletonPattern getInstance() {
return instance;
}
}
5.7 饿汉式,线程安全 (静态代码块形式)
public class SingletonPattern {
//Singleton对象属性
private static SingletonPattern singletonPattern;
//类加载时的时候初始化赋值
static {
singletonPattern = new SingletonPattern();
}
//获取唯一可用的对象
public static SingletonPattern getInstance() {
return singletonPattern;
}
}
一般来说,单例模式使用饿汉式实现就可以 饿汉式写法 和 静态内部类写法 就可以