前言

单例模式是最常用到的设计模式之一,比如封装网络请求框架时,RxJava+Retrofit的封装过程就用到了单例模式。顾名思义,保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,要确保这个类只有一个对象实例。

思路

单例模式要求类有一个方法用来返回对象的一个引用和获取该实例,必须是静态方法,一般使用getInstance。单利模式的实现分两步走:

  • 1.把类的构造定义为私有方法,这样别人就无法调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例
  • 2.类提供一个静态方法,若被调用,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用

单例模式的使用场景

单例模式的使用场景如下:

  • 1.整个项目需要一个共享访问点或共享数据
  • 2.创建一个对象需要效果贼多资源,比如访问I/O、数据库、线程池
  • 3.工具类对象

注意:

  • 1.构造函数不对外开放,一般为private
  • 2.通过一个静态方法或者枚举来返回单例类对象
  • 3.确保单例类的对象有且只有一个,尤其是在多线程的环境下
  • 4.确保单例类对象在反序列化时不会重新构建对象

单例类的构造函数私有化,可以保证Client不能通过new的方式创建对象。单例类会暴露一个公有的静态方法,Client只能调用该静态方法才能获取单例类唯一的对象,且在该过程中需要保证线程安全。

单例模式的写法

1.懒汉式-线程不安全写法

懒汉模式声明了一个静态对象,在第一次调用时初始化。虽然节约了资源,但是第一次加载时要初始化,反应要慢,且多线程下不能正常工作,因为一旦线程A进入了if语句中,还未来得及继续走,线程B也同时进来了,这样就不能保证单例了。

public class Singleton {private static Singleton singleton;//声明一个静态对象//私有构造,保证不能通过调用构造方法来实例化对象private Singleton(){}public static Singleton getInstance(){if (singleton==null){//第一次调用才会进行初始化,起到了lazy load的效果singleton=new Singleton();}return singleton;}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

调用只需要Singleton instance = Singleton.getInstance();
优点:延迟加载,需要的时候才会初始化实例对象
缺点:线程不安全,不可用

2.懒汉式-线程安全写法

加入了synchronized锁,并且支持延迟加载(lazy load)。但正是因为有锁,效率低下。每个线程获取类实例的时候,执行getInstance()方法都要进行同步,造成了不必要的同步开销。况且大部分情况下,我们都不需要同步。

public class Singleton {private static Singleton singleton;//声明一个静态对象private Singleton(){}public static synchronized Singleton getInstance(){if (singleton==null){//第一次调用才会进行初始化singleton=new Singleton();}return singleton;}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

优点:既保证了线程安全,又能实现lazy load延迟加载
缺点:在多线程中每次要获取实例对象都要先进行不必要的同步,效率低下。

3.懒汉式-线程安全同步代码块

同步方法效率太低,优化为同步代码块。但是这种方式依旧起不到线程同步作用,2个线程同时进入if条件语句,就会产生多个实例。

public class Singleton {private static Singleton singleton;//声明一个静态对象private Singleton(){}public static Singleton getInstance(){if (singleton==null){//同步代码块,依旧起不到同步的作用synchronized (Singleton.class){singleton=new Singleton();}}return singleton;}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

优点:既保证了线程安全,又能实现lazy load延迟加载
缺点:未起到同步作用

4.饿汉式-静态常量

public class Singleton {private final static Singleton singleton = new Singleton();private Singleton(){}public static Singleton getInstance(){return singleton;}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

优点:类装载就完成了实例化,避免了同步问题
缺点:没起到lazy load效果

5.饿汉式-静态代码块

public class Singleton {private static Singleton singleton;static {singleton=new Singleton();}private Singleton(){}public static Singleton getInstance(){return singleton;}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

优点:类装载就完成了实例化,避免了同步问题
缺点:没起到lazy load效果

6.双重检查模式DCL

使用volatile 修饰,起到了禁止指令重排序和内存可见性的作用。资源利用率高,首次调用getInstance方法才会去创建实例,但是首次加载速度慢。

public class Singleton {private volatile static Singleton singleton;private Singleton(){}public static Singleton getInstance(){if (singleton==null){ //为了不必要的同步synchronized (Singleton.class){if (singleton==null){ //singleton为null才会创建实例singleton = new Singleton();}}}return singleton;}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

优点:资源利用率高,第一次获取实例才会去创建
缺点:首次获取实例时间长,且存在高并发环境下造成的DCL失效

7.静态内部类

第一次加载Singleton类并不会初始化singleton,只有当虚拟机第一次调用getInstance方法加载SingletonHolder时才会初始化singleton。既保证线程安全,也使实例唯一。

public class Singleton {private Singleton(){}public static Singleton getInstance(){return SingletonHolder.singleton;}public static class SingletonHolder{private static final Singleton singleton = new Singleton();}//    private Object readResolve() throws ObjectStreamException{//        return singleton;
//    }
}

优点:线程安全、延迟加载lazy load、效率高

8.枚举

默认枚举创建是线程安全,且任何情况下都是单例。以上的单例模式创建,反序列化会重新创建对象:将一个单例对象写到磁盘,再读回来,从而获取到一个实例对象。反序列化提供了readResolve方法(控制对象的反序列化)。要想杜绝反序列化重新生成对象,就得把注释打开。

public enum Singleton{INSTANCE;public void doSomeThing(){//...}}

优点:默认线程安全、单例,简单明了
缺点:很少用,可读性不高

设计模式之单例模式学习笔记相关推荐

  1. 设计模式之禅学习笔记

    设计模式 一,六大设计原则[SOLID] 1,单一职责[SRP]:应该有且仅有一个原因引起类的变更. "职责"和"变化原因"都是不可度量的,因项目和实际环境而异 ...

  2. javaScript设计模式---(单例模式学习)

    单例模式 一个类只能有一个实例化对象.如页面中的弹出框蒙层,一个页面只需要一个. 实现方式:创建一个类,这个类包含一个方法,这个方法在没有对象存在的情况下,将会创建一个新的实例对象.如果对象存在,这个 ...

  3. 设计模式之观察者模式学习笔记

    前言 观察者模式,又叫作发布-订阅模式.一般的特点为对象间的关系为一对多,当一个对象被修改的时候,就会通知它依赖的对象 定义 定义对象间一种一对多的依赖关系,每当一个对象状态发生改变时,所有依赖于它的 ...

  4. 设计模式之装饰模式学习笔记

    前言 顾名思义,就是对已经存在的某些类进行装饰,以此来扩展某些功能.在不改变类文件和使用继承的情况下,动态的扩展一个对象的功能,是继承的替代方案之一.通过创建一个包装对象,即装饰包裹真实的对象. 定义 ...

  5. java 模块设计模式_Java9模块化学习笔记二之模块设计模式

    模块设计的原则: 1.防止出现编译时循环依赖(主要是编译器不支持),但运行时是允许循环依赖的,比如GUI应用 2.明确模块的边界 几种模块设计: API模块,聚合模块(比如java.base) 可选依 ...

  6. java/android 设计模式学习笔记(1)--- 单例模式

    前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...

  7. java/android 设计模式学习笔记(1)---单例模式

    前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...

  8. 设计模式学习笔记(1)——单例模式

    单例模式是常用的设计模式之一,作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,特点: 某个类只能有一个实例,避免重复实例化. 必须自行创建这个实例,不允许 ...

  9. 7 种 Javascript 常用设计模式学习笔记

    7 种 Javascript 常用设计模式学习笔记 由于 JS 或者前端的场景限制,并不是 23 种设计模式都常用. 有的是没有使用场景,有的模式使用场景非常少,所以只是列举 7 个常见的模式 本文的 ...

最新文章

  1. Android动态加载进阶 代理Activity模式
  2. hsv java_rgb-hsv-hsl-android.java
  3. 手持gps坐标转换参数求解方法及在excel中的实现_怎么在GIS office 软件中批量导入坐标点位...
  4. 用PyQt实现透明桌面时钟小部件
  5. eclipse 常用操作 持续更新
  6. 设计模式-关于模式的一些很基本的知识点
  7. LocalDateTime计算两个日期时间差
  8. JAVA分布式架构设计实例
  9. Gom引擎如何进行“称号系统”的设置详细介绍
  10. PHP获取Opcode及C源码
  11. 《深度学习》/《Deep Learning》——深度学习圣经的读书笔记
  12. 光猫,交换机和路由器的区别
  13. 今日来介绍关于淘宝相似商品搜索的API接口
  14. Android工具修复属性,Broken Android Data Extraction(安卓数据修复工具) V3.0.20 官方版
  15. 第三章 模糊查询与分组查询 ② 代码
  16. 行列式、逆矩阵、列空间和零空间(3Blue1Brown学习笔记)
  17. Win7系统经常提示显示驱动程序已停止响应并且恢复的解决办法
  18. 分享几个精美的个人简历模板,非常不错的简历,docx格式的可直接修改。
  19. 基于 STM32 的语音识别智能家居控制系统的设计(LD3320语音识别芯片+ESP8266 WIFI模块+DHT11温湿度采集+MQ系列 烟雾及可燃气体+蜂鸣器+步进电机模拟窗帘+OLED液晶显示+
  20. x200 vistar系统硬盘安装ubuntu9.10

热门文章

  1. layer.js 弹窗组件API文档
  2. 如何搭建亿级社交信息分享社交平台架构
  3. bzoj千题计划248:bzoj3697: 采药人的路径
  4. Sql Server中判断表或者数据库是否存在
  5. 选择HttpHandler还是HttpModule?
  6. 在RecyclerView的子布局中使用EditText在数据滚动后消失
  7. tvOS模拟器遥控的快捷键
  8. JAVA中操作符的优先级
  9. python调用zabbix api接口实时展示数据
  10. 不丹的启示:用国民幸福总值替代GDP