23种设计模式之《单例模式》
什么是单例模式
单例模式是23种设计模式中最简单和易用的模式。在某些情境下,如在一个上市公司中,有很多不同级别的员工,但是公司的CEO或者CTO都是只有一个的,CEO或者CTO在公司里就要求是一个单例。单例模式,就是某个类因实际情况的需要,要求在全局的范围内只能有唯一的实例对象,这个对象是常驻内存的,可以重复使用,降低重复创建对象的开销。
单例模式的特点
- 类的构造函数是私有的
- 在类内部实例化对象,并通过静态方法向外提供实例化的对象
下面主要讲解实现单例模式的方法以及它们的优缺点
单例模式的实现
单例模式的目的,就是要确保在全局范围内某个类的对象是唯一的。所以实现单例模式时,我们至少要考虑两个影响对象创建的因素。
- 在并发的环境下的线程安全
- 反序列化
饿汉实现
在类第一次加载时,就进行对象的实例化。
public class SingletonDemo {private final static SingletonDemo mSingletonDemo = new SingletonDemo();private SingletonDemo() {}public static SingletonDemo getInstance() {return mSingletonDemo;}}
复制代码
懒汉实现
在类加载时不进行对象的实例化,只在对象被第一次访问时,才进行对象的实例化。
public class SingletonDemo {private static SingletonDemo mSingletonDemo;private SingletonDemo() {}public static SingletonDemo getInstance() {if(mSingletonDemo == null) {mSingletonDemo = new SingletonDemo();}return mSingletonDemo;}}
复制代码
明显,在多线程的环境下,上面两种实现方式都不是线程安全的。为了实现线程安全,我们首先可以想到使用synchronized关键字。
线程安全的懒汉模式
public class SingletonDemo {private static SingletonDemo mSingletonDemo;private SingletonDemo() {}public static synchronized SingletonDemo getInstance() {if(mSingletonDemo == null) {mSingletonDemo = new SingletonDemo();}return mSingletonDemo;}}
复制代码
关于synchronized关键字说明一下,synchronized声明的静态方法,同时只能被一个执行线程访问,但是其他线程可以访问这个对象的非静态方法。即:两个线程可以同时访问一个对象的两个不同的synchronized方法,其中一个是静态方法,一个是非静态方法。
所以,当有多个线程同时访问getInstance静态方法时,多个其他的线程只能等待,这时只有一个线程能够访问getInstance方法,等这个线程释放后其他线程才能访问。这样就会影响速度和效率。
为了提高懒汉模式的速度和效率,可以减小锁的粒度和次数。
双重校验锁法
public class SingletonDemo {private static SingletonDemo mSingletonDemo;private SingletonDemo() {}public static synchronized SingletonDemo getInstance() {if(mSingletonDemo == null) {synchronized (SingletonDemo.class) {if(mSingletonDemo == null) {mSingletonDemo = new SingletonDemo();}}}return mSingletonDemo;}}
复制代码
从上面可以看到,只有在第一次访问时才会锁定和创建类的对象,之后的访问都是直接使用已经创建好的对象,这样减少锁定的次数和范围,以达到提高单例模式的效率。
但是,对象的实例化,并不是一个原子性操作。即第11行代码处,它可以分成下面三个步骤: 1、new SingletonDemo(),为SingletonDemo实例分配内存 2、调用SingletonDemo的构造器,完成初始化工作 3、将mSingletonDemo指向分配的内存空间
由于java处理器可以乱序执行,即无法保证2和3的执行顺序。这对双重校验锁法实现的单例模式有什么影响呢? 当第一个线程访问getInstance方法时,会锁定临界区(第9行到第13行代码),它实例化对象的顺序是1=>3=>2,而在这时如果有第二个线程来访问getInstance方法,由于第一个线程在处理器中执行完了3未执行2,第二个线程会马上得到实例对象,因为第一个线程的3已经执行完即mSingletonDemo已经不为空。当第二个线程使用没有初始化的对象时就会出现问题。
所以,双重校验锁法也不是完美的,在并发环境下依然可能出现问题。
静态内部类实现
public class SingletonDemo {private static SingletonDemo mSingletonDemo;private SingletonDemo() {}private static class SingletonHolder {private static final SingletonDemo INSTANCE = new SingletonDemo();}public static SingletonDemo getInstance() {return SingletonHolder.INSTANCE;}}
复制代码
第一次加载SingletonDemo类时并不会实例化INSTANCE,只有在第一次调用getInstance方法时,才会加载SingletonHolder内部类,创建SingletonDemo实例。这种方式不仅确保了线程安全,也保证单例对象的唯一性,同时也实现了单例对象的懒加载。
枚举实现
上面几种实现方式,可能会因为反序列化而创建新的实例,所以必须重写readResolve方法,在readResolve方法中返回已经创建的单例。
使用枚举可以很简单的实现单例模式,这也是Effective Java中提倡的方式。因为枚举本身就是类型安全的,并且枚举实例在任何情况下都是单例。
public enum SingletonEnumDemo {INSTANCE;public void justDoYourThing() {}
}
复制代码
枚举单例使用
SingletonEnumDemo.INSTANCE.justDoYourThing();
复制代码
容器实现
public class SingletonDemo {private static Map<String, Object> singletonMap = new HashMap<String, Object>();private SingletonDemo() {}public static void registerService(String key, Object instance) {if (!singletonMap.containsKey(key)) {singletonMap.put(key, instance);}}public static Object getService(String key) {return singletonMap.get(key);}}
复制代码
转载于:https://juejin.im/post/5ac4458151882555867fa2ed
23种设计模式之《单例模式》相关推荐
- java 23种设计模式 04 单例模式
java 23种设计模式 04 单例模式 一.什么是单例模式 单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象.也就是说,在整个程序空间中,该类只存在一个实例对象. ...
- 23种设计模式之单例模式、工厂模式、原型模式、建造者模式
系列文章目录 第一章:程序设计原则-单一职责.接口隔离.依赖倒置.里式替换 第二章:程序设计原则-开闭原则.迪米特法则.合成复用原则 文章目录 系列文章目录 一.设计模式简单介绍 1.1.什么是设计模 ...
- Java面试23种设计模式之单例模式的8种实现方式
单例模式8中实现方式 1.单例模式介绍 2.单例模式的八种方式 3.饿汉式(静态常量),这种单例模式可用,可能造成内存浪费. 4.饿汉式(静态代码块),这种单例模式可用,可能造成内存浪费. 5.懒汉式 ...
- 《23种设计模式之单例模式(4种实现)》
说在前头:本人为大二在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,能力有限,文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正.若 ...
- 23种设计模式之单例模式
单例模式 单例模式(Singleton Pattern)是一个比较简单的模式,其定义为:Ensure a class has only one instance,and provide a globa ...
- JAVA设计模式总结之23种设计模式
一.什么是设计模式 ...
- 23种设计模式之模板方法
23种设计模式总篇:chenmingyu.top/design/ 模板方法 模板方法属于行为型模式 定义:定义一个操作中的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定 ...
- JAVA设计模式总结之23种设计模式(重点!!!)
JAVA设计模式总结之23种设计模式: 一.什么是设计模式 设计模式遵循的原则有6个: 二.设计模式的三个分类 三.各分类中模式的关键点 四.概说23种设计模式 1.单例模式(Singleton) 2 ...
- java 的23种设计模式 单例模式
23种设计模式友情链接: 点击打开链接 单例模式: A.饿汉式单例模式 具体步骤: 1.声明一个私有的静态的最终的本类类型的对象并实例化 private static final Person ins ...
最新文章
- 常见的集合容器应当避免的坑
- pika-NoSQL原理概述
- 写markdown用于Github上readme.md文件
- 合肥python培训-合肥Python测试开发全栈核心课程
- tornado环境搭建
- 文本转换成htmldocument
- Python继承类的方式实现多线程及控制线程数
- Burpsuite爆破含CSRF-Token的程序
- [线程池] ------ 形象的描述线程池,用一个特好记的例子来记忆
- Web Broadcast Channel
- springboot 项目中在普通类中调用dao层的mapper 出现空指针异常
- 大数据之Superset
- 运营商5G商业模式研究
- Python去除文件名后缀
- u盘打不开,提示需要格式化怎么办?
- C4D玻璃材质调节方法
- MATLAB 数学应用 微分方程 一维偏微分方程 求解单个PDE
- windows编程学习感悟
- 使用OpenCV合成训练图片,同时生成labelme兼容格式的标注文件
- pe下找不到ssd硬盘_进入pe后找不到固态硬盘怎么解决