《23种设计模式(Java版)》| 单例模式(内附源码案例)。

简介: 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

1.png

一、概述


所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。


二、单例模式八种方式


饿汉式(静态常量)

//饿汉式(静态变量)
class Singleton{
  //1.构造器私有化 
  private Singleton() {
  }
  //2.在本类内部创建对象实例
  private final static Singleton instance=new Singleton();
  //3.提供一个公有的静态方法,返回实例对象
  public static Singleton getInstance() {
    return instance;
  }
}

饿汉式(静态代码块)

//饿汉式(静态代码块)
class Singleton{
  //1.构造器私有化 
  private Singleton() {
  }
  //2.在本类内部创建对象实例
  private static Singleton instance;
  static {
    ///在静态代码块中,创建单例对象
    instance=new Singleton();
  }
  //3.提供一个公有的静态方法,返回实例对象
  public static Singleton getInstance() {
    return instance;
  }
}

优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费


这种饿汉式方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法, 但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance就没有达到lazy loading的效果


这种单例模式可用,但是可能造成内存浪费


懒汉式(线程不安全)

// 懒汉式(线程不安全)
class Singleton{
  private static Singleton instance;
  private Singleton() {
  }
  //提供一个静态的公有方法,当方法使用时,才去创建对象
  public static Singleton getInstance() {
    if(instance==null) {
      instance=new Singleton();
    }
    return instance;
  }
}

起到了Lazy Loading的效果,但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。


在实际开发中,不要使用这种方式


懒汉式(线程安全,同步方法)


//懒汉式(线程程同步)
class Singleton{
  private static Singleton instance;
  private Singleton() {}
  //提供一个静态的公有方法,加入同步机制,解决线程安全
  public static synchronized Singleton getInstance() {
    if(instance==null) {
      instance=new Singleton();
    }
    return instance;
  }
}

解决了线程不安全问题。效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低。


在实际开发中,不要使用这种方式


懒汉式(线程安全,同步代码块


//懒汉式(线程安全,同步代码块)
class Singleton{
  private static Singleton instance;
  private Singleton() {}
  //提供一个静态的公有方法,加入同步机制,解决线程安全
  public static synchronized Singleton getInstance() {
    if(instance==null) {
      synchronized(Singleton.class){
        instance=new Singleton();
      }
    }
    return instance;
  }
}

这种方式,是对上面实现方式的改进,因为前面同步方法效率太低,改为同步产生实例化的的代码块但是这种同步并不能起到线程同步的作用。假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。


在实际开发中,不要使用这种方式


双重检查


//双重检查
class Singleton{
  private static volatile Singleton instance;
  private Singleton() {}
  //提供一个静态的公有方法,加入双重检查,解决线程安全,同时解决懒加载
  public static  Singleton getInstance() {
    if(instance==null) {
      synchronized (Singleton.class) {
        if(instance==null) {
          instance=new Singleton();
        }
      }
    }
    return instance;
  }
}

Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象,也避免的反复进行方法同步。 线程安全;延迟加载;效率较高。


在实际开发中,推荐使用这种单例设计模式


静态内部类

//静态内部类 推荐使用
class Singleton{
  private static volatile Singleton instance;
  //构造器私有化
  private Singleton() {}
  //写静态内部类,该类中有一个静态的属性Singleton
  private static class SingletonInstance {
    private static final Singleton instance=new Singleton();
  }
  //提供一个静态的公有方法,直接返回静态内部类的属性
  public static  Singleton getInstance() {
    return SingletonInstance.instance;
  }
}

这种方式采用了类装载的机制来保证初始化实例时只有一个线程。 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。


优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高

在实际开发中,推荐使用这种单例设计模式


枚举

//枚举实现
enum Single{
  INSTANCE;
  public void sayOK() {
    System.out.println("OK");
  }
}

这借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。


在实际开发中,推荐使用这种单例设计模式


三、在JDK源码应用分析


JDK中java.lang.Runtime就是经典的单例模式(饿汉式)


public class Runtime {
  //类内部创建对象实例化
    private static Runtime currentRuntime = new Runtime();
    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
     //提供静态方法返回实例对象
    public static Runtime getRuntime() {
        return currentRuntime;
    }
  //构造器私有化
    /** Don't let anyone else instantiate this class */
    private Runtime() {}
  }


四、总结Tips


单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能

当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new

单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)


相关文章
|
25天前
|
设计模式 存储 缓存
「全网最细 + 实战源码案例」设计模式——享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少大量相似对象的内存消耗。通过分离对象的内部状态(可共享、不变)和外部状态(依赖环境、变化),它有效减少了内存使用。适用于存在大量相似对象且需节省内存的场景。模式优点包括节省内存和提高性能,但会增加系统复杂性。实现时需将对象成员变量拆分为内在和外在状态,并通过工厂类管理享元对象。
165 92
|
21天前
|
设计模式 存储 算法
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
59 14
「全网最细 + 实战源码案例」设计模式——命令模式
|
21天前
|
设计模式 存储 Java
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
56 13
「全网最细 + 实战源码案例」设计模式——责任链模式
|
23天前
|
设计模式 算法 开发者
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
57 8
「全网最细 + 实战源码案例」设计模式——策略模式
|
23天前
|
设计模式 SQL 算法
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
64 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
|
13天前
|
JavaScript 安全 Java
智慧产科一体化管理平台源码,基于Java,Vue,ElementUI技术开发,二开快捷
智慧产科一体化管理平台覆盖从备孕到产后42天的全流程管理,构建科室协同、医患沟通及智能设备互联平台。通过移动端扫码建卡、自助报道、智能采集数据等手段优化就诊流程,提升孕妇就诊体验,并实现高危孕产妇五色管理和孕妇学校三位一体化管理,全面提升妇幼健康宣教质量。
42 12
|
29天前
|
设计模式 Java 开发者
「全网最细 + 实战源码案例」设计模式——适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,通过引入适配器类将一个类的接口转换为客户端期望的另一个接口,使原本因接口不兼容而无法协作的类能够协同工作。适配器模式分为类适配器和对象适配器两种,前者通过多重继承实现,后者通过组合方式实现,更常用。该模式适用于遗留系统改造、接口转换和第三方库集成等场景,能提高代码复用性和灵活性,但也可能增加代码复杂性和性能开销。
72 28
|
25天前
|
设计模式 存储 安全
「全网最细 + 实战源码案例」设计模式——组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式对待单个对象和对象集合,简化了复杂结构的处理。组合模式包含三个主要组件:抽象组件(Component)、叶子节点(Leaf)和组合节点(Composite)。通过这种模式,客户端可以统一处理简单元素和复杂元素,而无需关心其内部结构。适用于需要实现树状对象结构或希望以相同方式处理简单和复杂元素的场景。优点包括支持树形结构、透明性和遵循开闭原则;缺点是可能引入不必要的复杂性和过度抽象。
79 22
|
27天前
|
设计模式 前端开发 数据库
「全网最细 + 实战源码案例」设计模式——桥接模式
桥接模式(Bridge Pattern)是一种结构型设计模式,通过将抽象部分与实现部分分离,使它们可以独立变化,从而降低代码耦合度,避免类爆炸,提高可扩展性。其结构包括实现类接口、具体实现类、抽象类和精确抽象类。适用于多维度扩展类、隐藏实现细节、简化庞杂类以及运行时切换实现方法的场景。优点包括高扩展性、隐藏实现细节、遵循开闭原则和单一职责原则;缺点是可能增加代码复杂度。示例中展示了不同操作系统播放不同格式视频文件的实现。
50 19
|
17天前
|
人工智能 监控 安全
Java智慧工地(源码):数字化管理提升施工安全与质量
随着科技的发展,智慧工地已成为建筑行业转型升级的重要手段。依托智能感知设备和云物互联技术,智慧工地为工程管理带来了革命性的变革,实现了项目管理的简单化、远程化和智能化。
35 4