GOF设计模式之1:单例设计模式

1.单例设计模式核心作用:

保证一个类只有一个实例,并且提供了访问该实例的全局访问点

2.常见应用场景:

  • window的任务管理器
  • 项目中读取配置文件一般也是一个单例模式
  • 数据库连接池的设计也是采用单例模式,因为数据库连接是一种数据库资源
  • 操作系统的文件管理系统,也是单例模式,一个操作系统只能有一个文件系统
  • Application也是单例的应用(Servlet编程或者Android的Application类)
  • 在Spring中,每个bean默认也是单例的,这样的有点儿事Spring容器可以管理
  • 在Servlet编程中每个Servlet也是单例的
  • 在Spring MVC和Struts1框架中控制器对象也是单例

3.单例模式的优点

  • 由于单例模式只生产一个对象,减少了系统开销,当一个对象的产生需要的资源比较多的时候,比如读取配置文件、产生其它依赖对象时,则可以在应用启动的时候直接产生一个单例对象,然后永久驻存内存的方式来解决。
  • 单例模式可以在系统设置全局访问点,优化共享资源的访问。例如可以设计一个单例类,负责所有数据表的映射。

4.常见5中单例模式的实现方式:

主要

饿汉式:线程安全,调用效率高。但是不能延时加载

懒汉式:线程安全,调用效率不高。但是可以延迟加载

其它:

双重检锁式:由于JVM底层内部模型的原因,偶尔会出现问题,不建议使用

静态内部类式:线程安全,调用效率高,而且可以延迟加载

枚举单例:线程安全,调用效率高,不可延迟加载

饿汉式的示例代码:

public class Singleton01 {
    //类初始化的时候,立即加载这个对象(没有延时加载的优势)。加载类时,是线程安全的
    private static Singleton01 instance = new Singleton01();
    private Singleton01(){}
    //方法没有同步调用效率高
    public static Singleton01 getInstance(){
        return instance;
    }
}

饿汉式单例模式的代码中,static变量会在类装载的时候进行初始化,此时不会涉及到多个线程对象访问该对象的问题。虚拟机会保证只会装载一次该类,肯定不会发生并发访问的问题,因此可以省略synchronized关键字

问题:如果仅仅是加载本类,而不是要调用getInstance,甚至永远都没有调用,则会造成资源浪费。

懒汉式的示例代码

 1 package com.chunjiangchao.pattern.singleton;
 2 /**
 3  * 测试懒汉式单例模式
 4  */
 5 public class Singleton02 {
 6     //类初始化的时候,不初始化这个对象(延时加载,真正用的时候再创建)。
 7     private static Singleton02 instance = null;
 8     private Singleton02(){}
 9     ////方法同步,调用效率低!
10     public static synchronized Singleton02 getInstance(){
11         if(instance == null)
12             instance = new Singleton02();
13         return instance;
14     }
15 }

要点:延迟加载,懒加载真正用到的时候才会选择加载

问题:

资源利用率高了,但是每次调用getInstance()方法都要同步,并发效率较低。

双重检锁实现

 1 package com.chunjiangchao.pattern.singleton;
 2 /**
 3  * 测试DCL(双重检锁)单例模式
 4  *
 5  */
 6 public class Singleton03 {
 7     //类初始化的时候,不初始化这个对象(延时加载,真正用的时候再创建)。
 8     private volatile static Singleton03 instance = null;
 9     private Singleton03(){}
10     ////代码块同步,调用效率要比同步方法要快一些,由于JVM的原因在高并发的情况下会出现问题
11     public static  Singleton03 getInstance(){
12         if(instance == null){
13             synchronized (Singleton03.class) {
14                 if(instance == null)
15                     instance = new Singleton03();
16             }
17         }
18         return instance;
19     }
20 }

提高了执行 的效率,不必每次获取对象的时候都要进行同步,只有第一次才会进行同步创建。

问题:

由于编译器优化的原因和JVM底层内部模型原因,偶尔会出现问题,不建议使用。但是我们可以在instance前面添加volatile关键字,这样就没问题了。

静态内部类实现方式:(懒加载方式)

 1 package com.chunjiangchao.pattern.singleton;
 2 /**
 3  * 静态内部类单例模式
 4  * 这种方式:线程安全,调用效率高,并且实现了延时加载!
 5  */
 6 public class Singleton04 {
 7     private Singleton04(){}
 8     public static  Singleton04 getInstance(){
 9         return Inner.instance;
10     }
11     private static class Inner{
12         private static final Singleton04 instance = new Singleton04();
13     }
14 }

外部类没有static属性,则不会像饿汉式那样,上来就把对象造出来了

只有真正调用getInstance才会加载静态内部类。加载类时是线程安全的。instance 是static final类型,保证了内存中只有这样一个实例存在,而且只被赋值一次,从而保证了线程安全性。

兼并并发高效调用和延迟加载的优势。

换一句户说:静态内部有具备饿汉式和延迟加载的优势。

枚举实现单例:

 1 package com.chunjiangchao.pattern.singleton;
 2 /**
 3  * 枚举式实现单例模式(没有延时加载)
 4  */
 5 public enum Singleton05 {
 6     instance;//这个枚举元素,本身就是单例对象!
 7     public void operation(){
 8         //添加需要的操作
 9     }
10 }

优点:实现简单;枚举本身就是单例。由JVM从根本上提供保障。避免反射和序列化的漏洞

缺点:无延迟加载

5.如何选用这五种单例模式?

单例对象占用资源少,不需要延迟加载:

枚举好于饿汉式

单例对象占用资源大,需要延迟加载

静态内部类好于懒汉式

6.问题

反射可以破解上面(不包含枚举)的实现方式(防止的做法是在构造方法中手动抛出异常)

反序列化可以破解(不包含枚举)的实现方式

可以通过定义readResolve防止获得不同对象。反序列化的时候,如果对象所在的类定义了readResolve()方法(一种回调方法),返回自己创建的那个对象。

时间: 2024-10-04 03:46:42

GOF设计模式之1:单例设计模式的相关文章

设计模式整理_单例设计模式

单例设计模式,它确保一个类只有一个实例,并提供一个全局访问点. 由于单例设计模式对应的类只能创建一个对象,因此它所对应的方法必须是static(不是static只有创建对象才能调用). 以下是单例模式的一个经典实现:采用了延迟加载对象的例子. public class Single1 { private static Single1 single; //利用一个静态变量来记录Single1的唯一实例,这里没有直接声明,采用了延迟加载模式. private Single1(){} //把构造器声明

设计模式(一)__单例设计模式

先来介绍一下什么是设计模式,设计模式起先是从建筑行业借鉴来的,然后慢慢发展到了今天这个样子. 设计模式是解决问题最行之有效的思想,是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. java有23种设计模式,今天就先来介绍一种:单例设计模式 单例设计模式: 有时候当你需要保证一个类在内存中的对象唯一性的时候,比如多程序读取一个配置文件时,建议配置文件封装成对象.会方便操作其中数据,又要保证多个程序读到的是同一

设计模式之:单例设计模式

单例设计模式 单例设计模式概述 单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供. 优点 在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能. 缺点 没有抽象层,因此扩展很难. 职责过重,在一定程序上违背了单一职责 单例模式: 饿汉式:类一加载就创建对象 懒汉式:用的时候,才去创建对象 例子1:单例设计模式之饿汉式 public classStudent { // 构造私有 private Student()

设计模式学习笔记——单例设计模式

1.特点:只需一个实例时考虑. 2.概念:保证一个类仅有一个实例,并提供一个供访问的全局点. 3.类图: 4程序实现: 1)懒汉式:对于懒汉模式,我们可以这样理解:该单例类非常懒,只有在自身需要的时候才会行动,从来不知道及早做好准备.它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象,然后返回,如果已有对象就不再创建,立即返回.懒汉模式只在外部对象第一次请求实例的时候才去创建.懒汉模式,它的特点是运行时获得对象的速度比较慢,但加载类的时候比较快.它在整个应用的生命周期只有一部分时

单例设计模式

一:单例设计模式的定义 单例设计模式,顾名思义,就是在整个程序运行过程中,只向外界提供一个对象,这样做可以避免资源的浪费,例如 我们打开回收站或者ppt时,只会启动一个窗口. 单例模式的java实现: 1:饿汉式 1 /** 2 * 3 */ 4 package com.hlcui.singleton; 5 6 /** 7 * @author Administrator 饿汉式单例类 8 */ 9 public class SingletonDemo { 10 // 1:内部创建一个对象 11

IOS开发之单例设计模式

本文将从四个方面对IOS开发中的单例设计模式进行讲解: 一.什么是单例设计模式 二.我们为什么要用单例设计模式 三.单例设计模式的基本用法 四.自定义单例设计模式代码的封装 一.什么是单例设计模式 所谓单例,即是单个的实例化对象,保证一个类有且仅有一个实例.通常情况下,当我们对一个类实例化时(如:alloc.new等),并不能保证每次实例化的对象是唯一的实例.那么为了保证该类可在多次实例化的过程中保证内存地址不变,就需要引入单例设计模式. 二.我们为什么要用单例设计模式 1.Singleton

java设计模式_single(单例设计模式)

设计模式:解决某一类问题最行之有效的方法,java中有23种设计模式 一.单例设计模式概述: 1.解决一个类在内存中只有一个对象(保证一个类仅有一个实例,并提供一个访问他的全局访问点)  2.要保证对象的唯一: 1.为了避免其他程序过多的建立该类对象,先禁制其他程序建立该类对象 2.为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象 3.为了 方便其他程序对自定义对象的访问,可以对外提供一些访问方式 3.代码实现步骤: 1.将构造函数私有化 2.在类中创建一个本类对象 3.给外部提供

iOS常用设计模式——单例设计模式

单例设计模式详解 单例设计模式详解 基本概念 在IOS中使用单例模式的情况 非ARC环境创建单例模式的基本步骤 非ARC环境具体代码实现 ARC环境创建单例模式的基本步骤 基本概念 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问 在IOS中使用单例模式的情况 1.如果说创建一个对象会耗费很多系统资源,那么此时采用单例模式,因为只需要一个实例,会节省alloc的时间 2.在IOS开发中,如果很多模

单例设计模式 --c#

单例设计模式:在单例设计模式中我们要保持对象始终是唯一的 参考代码: class SingleObject { private SingleObject() { } private static SingleObject _single = null; public static SingleObject GetSingle() { if (_single == null) { _single = new SingleObject(); } return _single; } public Fo

构造私有化和单例设计模式

以下的代码对构造方法进行了私有化封装,但这样封装后我们在类外需要实例化对象是会出现错误,因为构造方法是私有的,所以无法实例化. 1 class Singleton{ 2 private Singleton() {} 3 public void print() { 4 System.out.println("hello world"); 5 } 既然在外部不能实例化对象,我们可以在类的内部实例化对象. 1 class Singleton { 2 // 在类的内部进行实例化对象 3 pri