1、定义
确保一个类只有一个实例,并且自行实例化,为整个系统提供实例
2、要点
从上面这句描述可以看出有三个要点,从具体实现来讲这三个要点:
- 单例模式的类只提供私有的构造函数
- 类定义中含有一个该类的静态私有对象
- 该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象
3、实现
3.1、饿汉式
public class HungrySingleton {
//构造函数有private,防止通过new创建更多对象,确保只要一个对象
private HungrySingleton(){
}
//在类初始化时,已经自行实例化,所以是线程安全的
private static final HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();
public static HungrySingleton getInstance(){
return HUNGRY_SINGLETON;
}
}
优点:写法简单,线程安全
缺点:没有懒加载的效果,如果没有使用过的话会照成内存浪费
可用性:可用
3.2、懒汉式(线程安全)
public class LazySingleton {
private LazySingleton() {
}
private static LazySingleton singleton = null;
//加上synchronized同步,线程安全
public synchronized static LazySingleton getInstance(){
if (singleton == null){
//在第一次调用getInstance()时才实例化,实现懒加载,所以叫懒汉式
singleton = new LazySingleton();
}
return singleton;
}
}
优点:实现了懒加载效果,线程安全
缺点:效率低,使用synchronized会照成不必要的同步开销,而且大部分情况下不需要使用同步
可用性:不推荐
3.3、双重检查锁定DCL
public class DCLSingleton {
//volatile 能够防止代码的重排序,保证得到的对象是初始化过
private volatile static DCLSingleton singleton;
private DCLSingleton() {
}
public static DCLSingleton getInstance(){
if (singleton == null){//第一次检查,避免不必要的同步
synchronized (DCLSingleton.class){
if (singleton == null){//第二次检查
singleton = new DCLSingleton();
}
}
}
return singleton;
}
}
优点:实现懒加载效果,线程安全,效率较高
缺点:volatile影响一点性能,高并发情况下有一定的缺陷,某些情况下DCL会失效,虽然概率较小。
可用性:推荐
3.4、静态内部类
public class StaticSingleton {
private StaticSingleton() {
}
//静态内部类
private static class SingleTonHolder{
private static final StaticSingleton singleton = new StaticSingleton();
}
public static StaticSingleton getInstance(){
//第一次调用getInstance方法时才加载SingletonHolder并初始化sInstance
return SingleTonHolder.singleton;
}
}
优点:懒加载,线程安全,效率高
可用性:推荐
3.5、枚举单例
public enum EnumSingleton {
INSTANCE; //定义一个枚举的元素,它就是Singleton的一个实例
public void whatTodo() {
}
}
优点:写法简单,线程安全,能防止反序列化重新创建新的对象
缺点:可读性低,枚举会比静态常量多一点点内存
可用性:可使用
4、场景
- 工具类对象
- 频繁访问数据库或文件的对象
- 创建对象时耗时过多或者耗资源多的,又经常使用到的对象
5、优点
- 内存中只有一个对象,节省系统资源
- 避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作
6、缺点
- 单例对象如果持有context,那么很容易引发内存泄漏
- 单例一般没有接口,很难拓展