单例模式介绍
单例模式是我们最常用使用最广泛的模式之一。在很多的应用场景下为了避免多次重复创建对象如:网络请求、缓存、数据库操作等都是很消耗资源的。因此在使用这个模式时,单例对象类必须保证只有一个实例存在。
单例的定义
确保某个类只有一个实例化对象。
单例的使用场景
单例设计的目的是保证某个类的实例只有一份。重复创建对象是会产生资源的消耗。向具体的网络请求、数据库操作、IO操作就可以考虑使用该模式。
单例的实现方式
- 懒汉模式
懒汉模式在第一次调用 getInstace() 时进行初始化。相对应也为该方法加上了synchronized 关键字,处理在多线程情况下保证单例对象的唯一性。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstace() {
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优点:只有在使用的时候才会被实例化,节约资源。
缺点:首次加载需要实例化,反应稍慢。每次调用 getInstance() 都需要进行同步,造成不必要的同步开销,一般不建议使用。
- 双重校验(DCL) 模式
该模式既能保证在使用的时候获取实例,又能保证线程安全,并且单例对象初始化之后使用getInstance不在进行不必要的同步开销。
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstace() {
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
该首先会经过如下几步:
- 为该单例分配内存
- 调用构造函数,初始化成员字段
- 将 instance 指向分配的内存空间
在JDK 1.5 之后调整了JVM,使用了关键字volatile ,将instance 对象直接定义为 private volatile static Singleton instance, 可以保证获取对象每次从主内存中读取,当然volatile 在一定程度上会影响性能,但为保证程序的正确性,在一些性能上可以忽略。
优点:首次执行getInstance 才会被实例化,效率高。资源利用率高。
缺点:首次加载稍慢,由于Java 内存模型原因偶尔会失败。
- 静态内部类模式
提倡使用该方式既能保证线程的同步,又能保证对象的唯一性。同时有延迟了类的实例化。
public class Singleton {
private Singleton() {
}
public static synchronized Singleton getInstace() {
return SingletonHodler.instance;
}
private static class SingletonHodler{
private static final Singleton instance = new Singleton();
}
}
优点:第一次加载 Singleton 时,不会初始化 instance,在执行Singleton getInstance 方法时instance才会被实例化。
- 枚举模式
默认枚举创建的实例都是线程安全的。而且任何情况下都是一个实例化对象。
public enum Singleton {
INSTANCE;
public void printInfo(){
System.out.println("日志信息输出");
}
}
优点:写法简单,既能保证线程同步又能保证对象的唯一性。
- 容器模式
通过使用HashMap 容器的形式将多种单例进行统一管理,在使用时通过key 获取对应的实例化对象降低耦合度,隐藏内部实现。
public class Singleton {
private static HashMap<String,Object> hashMap = new HashMap<>();
private Singleton() {
}
public static void register(String key,Object instance){
if (isKeyEmpty(key)) {
return;
}
if (hashMap == null){
hashMap = new HashMap<>();
}
if (!hashMap.containsKey(key)){
hashMap.put(key,instance);
}
}
public static Object getInstace(String key){
if (hashMap == null){
return null;
}
if (isKeyEmpty(key)) {
return null;
}
return hashMap.get(key);
}
public static boolean isKeyEmpty(String key){
if (key == null || "".equals(key)){
return true;
}
return false;
}
}
经过上面的几种单例模式介绍,推荐使用静态内部类模式实现的单例模式。具体的使用还是视情况而定。从而在保证唯一性的情况下还能保证线程同步,达到节约资源的目的。
网友评论