共计 1861 个字符,预计需要花费 5 分钟才能阅读完成。
设计模式千千万,总是单例最常见。
单例模式的定义
保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。
六种单例的创立形式
1. 饿汉式
public class Singleton {private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {return instance;}
}
长处:
基于类的加载机制,防止了多线程同步问题,加载速度快。
毛病:
在类加载的时候就实现初始化,没有懒加载,如果没有应用这个实例,会造成内存节约。
2. 懒汉式 - 线程不平安版
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {if(instance == null){instance = new Singleton();
}
return instance;
}
}
长处:
第一次调用是才初始化对象,避免浪费资源
毛病:
加载速度慢,线程不平安
3. 懒汉式 - 线程平安版(synchronized 加锁)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {if(instance == null){instance = new Singleton();
}
return instance;
}
}
长处:
多线程中保障线程平安
毛病:
每次获取对象实例,都须要进行同步,造成不必要的同步开销。
4. 双重校验锁
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {if(instance == null){synchronized(Singleton.class) {if(instance == null) {instance = new Singleton();
}
}
}
return instance;
}
}
长处:
线程平安,懒加载,缩小同步开销
毛病:
第一个获取对象速度稍慢,但其在某些状况下也会呈现生效的状况,并不是完满的形式。
这外面应用了两次判空:第一次为了不必要的加锁同步,第二次是确保在 instance 为 null 的状况下才创立实例,防止屡次创立。
办法中还是用了关键字 volatile 对变量进行润饰,有如下几个作用:
1. 在 Java 内存模型中 volatile 能够保障可见性,及避免程序指令重排序。
2. 对象的创立分为如下几个步骤:
instance = new Singleton();
- 1. 为 instance 分配内存空间
- 2. 初始化 instance
- 3. 将 instance 指向内存地址
如果不加 volatile 的话,程序的执行程序就可能变成 1 ->3->2, 多线程中就会导致线程获取一个没有初始化的实例。例如线程 a 执行了 1,3, 此时线程 b 调用 getInstance()发现 instance 不为空,返回 instance, 但此时 instance 还未初始化。
5. 动态外部类
public class Singleton {private Singleton() {}
public static Singleton getInstance() {return SingletonHolder.sInstance;}
private static class SingletonHolder {private static final Singleton sInstance = new Singleton();
}
}
第一次加载类的时候不会初始化 instance, 只有第一次调用 getInstance()的时候才会进行加载 SingleHolder 并初始化 instance, 保障线程平安, 也能保障实例惟一,举荐应用这种形式。
6. 枚举
public enum Singleton {
INSTANCE;
public void doSomeThing(){}
}
默认枚举单例的创立是线程平安的,并且任何状况下都是单例。
以上就是 6 中常见的单例创立模式,按需应用吧。
单例的应用场景
- 整个我的项目须要一个共享拜访点或者数据
- 创立一个对象须要消耗的资源太多,比方拜访数据库资源等
- 工具类对象