目录
- 1.单例模式简介
- 2.单例模式关键点
- 3.单例模式UML图
- 4.单例模式的实现方式
- 饿汉式
- 懒汉式
- 同步锁懒汉式
- DCL懒汉式
- 枚举
- 静态内部类
- 5.使用场景
- 6.单例模式和静态类的区别
- 7.单例模式相关面试题
1.单例模式(Singleton)
- 最基础,使用最广泛的设计模式
- 创建型设计模式
- 一个类有且仅有一个实例,并且自行实例化向整个系统提供
2.单例模式关键点
- 构造函数私有化,即声明为private
- 通过一个静态方法或者枚举返回单例类对象
- 确保单例类的对象有且只有一个,尤其要注意多线程的场景
- 确保单例类对象在反序列化时不会重新创建对象
3.单例模式UML图

4.单例模式的实现方式
4.1 饿汉式单例(Eager Singleton)
public class Singleton {
//1.创建私有静态成员变量并实例化
private static Singleton mSingleton = new Singleton();
//2.将构造函数私有化,使外界无法直接实例化
private Singleton() {
}
//3.提供公开方法返回创建的实例化对象
public static Singleton getInstance() {
return mSingleton;
}
}
- 优点:类加载的时候,会创建Singleton 实例。并且因为虚拟机保证了类只会加载一次,所以这种写法保证线程的安全性
- 缺点:也是由于类加载的时候就会创建实例,会降低内存的使用率,浪费不必要的资源。如果单例类使用频繁的情况下,可以使用这种方式。
- 访问量大或者访问线程较多的时候,可以使用饿汉式。以空间换时间
4.2 经典的懒汉式单例(Lazy Singleton)【不推荐】
public class Singleton {
private Singleton() {}
private static Singleton instance=null;
public static Singleton getInstance() {
if (instance== null) {
instance= new Singleton();
}
return instance;
}
}
- 优点:实现了懒加载,在第一次使用的时候才会实例化单例对象
- 缺点:非线程安全,在多并发情况,可能出现多个Singleton 实例,导致单例失效。
- 访问量小的时候,可以使用懒汉式。以时间换空间
4.3 加同步锁的懒汉式
public class Singleton {
private Singleton() {}
private static Singleton instance=null;
public static synchronized Singleton getInstance() {
if (instance== null) {
instance= new Singleton();
}
return instance;
}
}
4.4 DCL懒汉式
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
if(null == instance) { // 线程二检测到instance不为空
synchronized (Singleton.class) {
if(null == instance) {
instance = new Singleton(); // 线程一被指令重排,先执行了赋值,但还没执行完构造函数(即未完成初始化)
}
}
}
return instance; // 后面线程二执行时将引发:对象尚未初始化错误
}
}
- 优点:资源利用效率高,第一次执行getInstance时单例对象才会被实例化,效率高
- 缺点:第一次加载时反应稍慢,也由于Java内存模型的原因偶尔会失败。高并发环境下也有一定的缺陷,虽然发生的概率比较小。
4.5 枚举 【不推荐】
enum Singleton{
INSTANCE;
}
- 优点:线程安全,防止反序列化重新创建新的对象
- 缺点:没有实现懒加载,并且Android中不推荐用枚举,内存消耗较大。
4.6 静态内部类【推荐】
public class Singleton {
private Singleton(){
}
private static class SingletonHolder{
private final static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
静态内部类因为只会加载一次,所以保证了线程安全。
内部类是在第一次使用的时候才会进行加载,实现了懒加载
5.单例模式的使用场景
- 需要频繁的进行创建和销毁的对象;
- 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
- 工具类对象;
- 频繁访问数据库或文件的对象。
- 确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个
6.单例模式和静态类的区别
http://blog.sina.com.cn/s/blog_4adc4b090102w1j1.html
7.单例模式相关面试题
一般引入单例模式的相关问题有两种情况,一是简单粗暴直接问你会什么设计模式,二是问你第三方的框架,然后问框架用了哪些设计模式,比如EventBus用了DCL的单例。
-
问题1.单例的写法,UML图,以及各种写法的优点和缺点?(可能需要手写单例)
- 单例写法比较多,我这里记录了6种,还有其他的方式,比如容器。能写出常见几种就行。
- 问题2.什么情况下使用单例?(毕竟设计模式不能滥用)
- 问题3.构成单例模式的关键点?
- 问题4.单例和静态类的区别?
网友评论