设计模式——小谈单例
来源:互联网 发布:linux 复制命令 编辑:程序博客网 时间:2024/06/14 07:23
小谈单例模式
一、引子
不出意外,谈到设计模式,大家第一个想到的应该会是单例模式,因为这是应用最广的设计模式之一,并且也相对简单一点。
在诸如使用线程池、缓存、网络连接、访问数据库以及文件(IO)读写等情景下,产生一个对象需要消耗大量的资源。
而我们都知道,单例模式要求一个单例类只能保证有一个实例化对象。
因此,在类似的一些情景下,使用单例能有效的减少资源的消耗,提高效率。
So,就让我们一起来看看单例模式吧。
二、正文
1、常见的单例的特点
1.1、构造方法私有化,即采用private修饰
1.2、一般通过暴露一个静态的方法返回单例类的对象
1.3、确保单例类只有一个对象(特别注意多线程情况下)
1.4、确保在【反序列化】时,不会重新构建对象
一般情况下,单例类的特点可用上述四点说明。
2、分门别类看单例
2.1、饿汉式
饿汉式是最简单的单例类实现方式。我们常见的有关单例类的代码描述,一般情况下就是饿汉式。具有帮助我们理解上述四大特点的作用,但在实际工程中,并不常用。在此贴出举例代码如下:
public class SingletonDemo1{ private static SingletonDemo1 mSingleInstance = new SingletonDemo1(); //私有化构造方法 private SingletonDemo1(){ } //提供公有的静态方法,暴露接口供外部调用获取单例类 public static getSingleInstance(){ return mSingleInstance; }}
【☆☆☆】可以看到:饿汉式中,静态对象在声明时已经完成了初始化操作。
2.2、懒汉式
由于饿汉式不具备实际上的应用效果,那么我们再来看一种更进一步的单例类写法—懒汉式。
public class SingletonDemo2{ private static SingletonDemo2 mSingleInstance; //私有化构造方法 private SingletonDemo2(){ } //提供公有的静态方法,暴露接口供外部调用获取单例类 public static synchronized SingletonDemo2 getSingleInstance(){ if (mSingleInstance == null) { mSingleInstance = new SingletonDemo2(); } return mSingleInstance; }}
很明显,这里的实例对象是在共有的方法被调用时才实例化。与此同时,添加了【synchronized】关键字来修饰,能保证在多线程情况下,单例对象的唯一性。
但是,有一点需要注意:假设mSingleInstance已经被实例化,但是每次调用相应的方法都会进行【同步】,这导致了资源的浪费。
因此,懒汉式也不推荐日常使用。
2.3、静态内部类单例模式
public class SingletonDemo3{ //私有化构造方法 private SingletonDemo3(){} //提供公有的静态方法,暴露接口供外部调用获取单例类 public static SingletonDemo3 getSingleInstance(){ return SingletonHolder.sInstance; } //静态内部类 private static class SingletonHolder{ private static final sInstance = new SingletonDemo3(); }}
通过代码可以发现,只有在第一次调用getSingleInstance()方法时,sInstance才会被初始化。
2.4、Double CheckLock式
大名鼎鼎的DCL实现方式:
public class SingletonDemo4{ //【☆☆☆】特别注意【volatile】关键字的修饰 private volatile static SingletonDemo4 mSingleInstance = null; //私有化构造方法 private SingletonDemo4(){ } //提供公有的静态方法,暴露接口供外部调用获取单例类 public static synchronized SingletonDemo4 getSingleInstance(){ if (mSingleInstance == null) { synchronized(SingletonDemo4.class){ if (mSingleInstance == null) { mSingleInstance = new SingletonDemo4(); } } } return mSingleInstance; }}
可以看到,这里执行了两次判空操作。第一次是为了避免不必要的同步,第二次是为了使得在对象为null时创建。
关于DCL中【volatile】关键字的修饰,这里特别附上一篇文章供大家参考:java单例真的写对了么
2.5、枚举式(据称是最佳单例实现模式)
嗯,除了写起来非常简单,也没有什么更合适来形容枚举了。
public enum SingletonDemo5{ SINGLEINSTANCE;}
【☆☆☆】特别注意的是:java中默认枚举实例的创建是线程安全的,并且任何情况下都是单例。
3、序列化与反序列化
额外补充一点序列化与反序列化的知识。
先看大白话定义:
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。
序列化我们用的比较多,因此这里重点来看反序列化。
反序列化就是将字节序列恢复成java对象。而构造一个java对象是需要调用其构造方法的,我们都知道单例模式中构造方法是私有化的,那么这里应该怎么考虑这个问题?
只需要在单例类中加入一个钩子方法:readResolve()即可
private Object readResolve() throws ObjectStreamException { return singleINstance;}
添加了上述方法,就能保证反序列化时返回我们的单例对象,而不是再重新创建违反了单例原则。
- 设计模式——小谈单例
- 设计模式——装饰设计模式
- 设计模式——装饰设计模式
- 设计模式——策略设计模式
- 设计模式——状态设计模式
- 设计模式——命令设计模式
- 设计模式——代理设计模式
- 设计模式——原型设计模式
- 设计模式——迭代器设计模式
- 设计模式——组合设计模式
- 设计模式——访问设计模式
- 设计模式——模板设计模式
- 设计模式——装饰设计模式
- 设计模式——工厂设计模式
- 设计模式——原型设计模式
- 设计模式——观察者设计模式
- 设计模式——空设计模式
- 设计模式——设计模式原则
- 7.5提取联通区域的轮廓
- Bellman-ford最短路算法
- android中build.gradle文件简单说明
- 构造函数模式扩展
- 关于花生壳动态ip映射的一点唠叨
- 设计模式——小谈单例
- Socket到底是什么?
- 一个页面从输入URL到页面加载显示完成,这个过程都发生什java 基础知识-数组的7种算法(排序、求和、最值、遍历...)么?
- 继承
- 【poj 2299】 Ultra-QuickSort 【Waterloo local 2005.02.05】
- 20171013学习日记 CSS
- C Looooops(扩展欧几里得)
- PAT 1003.我要通过!(20) java
- 线代008 矩阵的运算