设计模式(四):单例模式
- [1. 单例模式的介绍](#1. 单例模式的介绍)
- [2. 单例模式的类图](#2. 单例模式的类图)
- [3. 单例模式的实现](#3. 单例模式的实现)
-
- [3.1 懒汉式(线程不安全)](#3.1 懒汉式(线程不安全))
- [3.2 懒汉式(线程安全)](#3.2 懒汉式(线程安全))
- [3.3 饿汉式](#3.3 饿汉式)
- [3.4 静态内部类](#3.4 静态内部类)
- [3.5 枚举](#3.5 枚举)
1. 单例模式的介绍
单例模式
(Singleton Pattern)属于创建型模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
优点:
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例
- 避免对资源的多重占用。
缺点:
- 没有接口,不能继承。
- 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外部怎么样来实例化。
2. 单例模式的类图
3. 单例模式的实现
3.1 懒汉式(线程不安全)
这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized
,所以严格意义上它并不算单例模式。
java
package blog;
public class SingleObject {
private static SingleObject instance;
private SingleObject() {}
public static SingleObject getInstance() {
if (instance == null) {
instance = new SingleObject();
}
return instance;
}
}
3.2 懒汉式(线程安全)
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
java
package blog;
public class SingleObject {
private volatile static SingleObject instance;
private SingleObject() {}
public static SingleObject getInstance() {
if (instance == null) {
synchronized (SingleObject.class) {
if (instance == null) {
instance = new SingleObject();
}
}
}
return instance;
}
}
3.3 饿汉式
这种方式比较常用,没有加锁,执行效率会提高。但在类加载时就初始化,浪费内存。
java
package blog;
public class SingleObject {
private static final SingleObject instance = new SingleObject();
private SingleObject() {}
public static SingleObject getInstance() {
return instance;
}
}
3.4 静态内部类
这种方式是 SingleObject
类被装载了,INSTANCE
不会被初始化。因为SingleObjectHolder
类没有被主动使用,只有通过显式调用 getInstance
方法时,才会显式装载SingleObjectHolder
类,从而实例化INSTANCE
。即实现了延迟加载,也保证线程安全。
java
package blog;
public class SingleObject {
private static class SingleObjectHolder {
private static final SingleObject INSTANCE = new SingleObject();
}
private SingleObject() {}
public static SingleObject getInstance() {
return SingleObjectHolder.INSTANCE;
}
}
3.5 枚举
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它不仅能避免多线程安全问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
java
package blog;
public class SingleObject {
enum SingletonEnum {
INSTANCE;
private final SingleObject unique;
SingletonEnum() {
unique = new SingleObject();
}
public SingleObject getInstnce(){
return unique;
}
}
private SingleObject() {}
public static SingleObject getInstance() {
return SingletonEnum.INSTANCE.getInstnce();
}
}