Java设计模式——单例模式(Singleton Pattern)

简介: Java设计模式——单例模式(Singleton Pattern)

从上一篇文章Java设计模式——装饰模式(Decorator Pattern)中估计大家都已经对java设计模式有了初步的理解,今天呢,阿Q就给大家讲一下另一种设计模式——单例设计模式。首先我们先来了解一下它的概念,单例模式是设计模式中最简单的形式之一,这一模式的目的是使得类的一个对象成为系统中的唯一实例,也就是保证类在内存中只有一个对象。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。它主要是为了解决全局使用的类频繁地创建与销毁浪费系统资源。

必要条件

单例模式的必要条件有三个:一是类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

何时使用

当您想控制实例数目,节省系统资源的时候。

简单案例

首先需要创建一个单例类

public class SingleObject {
  //创建 SingleObject 的一个对象
  private static SingleObject instance = new SingleObject();
  //让构造函数为 private,这样该类就不会被实例化
  private SingleObject(){}
  //获取唯一可用的对象
  public static SingleObject getInstance(){
     return instance;
  }
  public void showMessage(){
     System.out.println("Hello World!");
  }
}

创建main函数:

public class SingletonPatternDemo {
    public static void main(String[] args) {
        //不合法的构造函数
        //编译时错误:构造函数 SingleObject() 是不可见的
        //SingleObject object = new SingleObject();
        //获取唯一可用的对象
        SingleObject object = SingleObject.getInstance();
        //显示消息
        object.showMessage();
    }
}

执行结果为:Hello World!

实现方式

一、饿汉式(开发用这种方式)——拿空间换时间

饿汉式最明显的标志就是在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。这种方式比较常用,但容易产生垃圾对象。它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

优点:没有加锁,执行效率会提高。

缺点:类加载时就初始化,浪费内存。

class Singleton {
   //1,私有构造函数,为了让外界不能创建Singleton的对象
   private Singleton(){}
   //2,创建本类对象(外界不能创建,但是本类可以创建)
   /*加private 是为了不让外界随意的更改对象s 。 加static 是为了让他是静态变量优先于
   对象而存在,当用类名调用getInstance()时候,如果s前面不加static是不可以的,因为静态
   的不能直接访问非静态的*/
   private static Singleton s = new Singleton();
   //3,对外提供公共的获取方法,获取唯一的 s 对象
   public static Singleton getInstance() {
       return s;
  }
}

二、懒汉式(线程不安全)

这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。

public class Singleton {  
   //1,私有构造函数
   private Singleton (){}  
//2,声明一个本类的引用
   private static Singleton instance;  
   //3,对外提供公共的访问方法
   public static Singleton getInstance() {  
  if (instance == null) {  
      instance = new Singleton();  
  }  
  return instance;  
  }  
}

三、懒汉式(线程安全)——拿时间换空间

这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。

优点:第一次调用才初始化,避免内存浪费。

缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

class Singleton {
   //1,私有构造函数
   private Singleton(){}
   //2,声明一个本类的引用
   private static Singleton s;
   //3,对外提供公共的访问方法
   public static sychronized Singleton getInstance() {
       if(s == null)
           //线程1,线程2
           s = new Singleton();
       return s;
  }
}

四、双检锁/双重校验锁(DCL,即 double-checked locking)

这种方式采用双锁机制,安全且在多线程情况下能保持高性能。getInstance() 的性能对应用程序很关键。

public class Singleton {  
    //volatile关键字会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getInstance() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
        }  
        return singleton;  
    }  
}

五、登记式/静态内部类

这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟饿汉式方式不同的是:饿汉式方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比饿汉式方式就显得很合理。

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}

JDK中单例模式应用

Runtime类是一个单例类
Runtime r = Runtime.getRuntime();
r.exec("shutdown -s -t 300");//300秒后关机
r.exec("shutdown -a");//取消关机

单例模式的优点与缺点

优点

一、实例控制:单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

二、灵活性:因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点

一、开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

二、可能的开发混淆:使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

三、对象生存期:不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。

单例类图

image.pngimage.gif


相关文章
|
4天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
13 2
|
9天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
6天前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy<T>` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
15 1
|
10天前
|
设计模式 缓存 数据库连接
探索PHP中的设计模式:单例模式的实现与应用
在PHP开发中,设计模式是提高代码可复用性、可维护性和扩展性的重要工具。本文将深入探讨单例模式(Singleton Pattern)的基本概念、在PHP中的实现方式以及实际应用场景。单例模式确保一个类仅有一个实例,并提供全局访问点。通过具体代码示例和详细解释,我们将展示如何在PHP项目中有效利用单例模式来解决实际问题,提升开发效率和应用性能。
|
2天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
本教程详细讲解了Kotlin中的单例模式实现,包括饿汉式、懒汉式、双重检查锁、静态内部类及枚举类等方法,适合需要深入了解Kotlin单例模式的开发者。快速学习者可参考“简洁”系列教程。
6 0
|
2天前
|
设计模式 存储 数据库连接
Python编程中的设计模式之美:单例模式的妙用与实现###
本文将深入浅出地探讨Python编程中的一种重要设计模式——单例模式。通过生动的比喻、清晰的逻辑和实用的代码示例,让读者轻松理解单例模式的核心概念、应用场景及如何在Python中高效实现。无论是初学者还是有经验的开发者,都能从中获得启发,提升对设计模式的理解和应用能力。 ###
|
5天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
5天前
|
设计模式 存储 安全
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和重用性的关键技术之一。本文将深入探讨单例模式(Singleton Pattern)的原理、实现方式及其在PHP中的应用,同时通过实例展示如何在具体的项目场景中有效利用单例模式来管理和组织对象,确保全局唯一性的实现和最佳实践。
|
6天前
|
设计模式 SQL 安全
【编程进阶知识】Java单例模式深度解析:饿汉式与懒汉式实现技巧
本文深入解析了Java单例模式中的饿汉式和懒汉式实现方法,包括它们的特点、实现代码和适用场景。通过静态常量、枚举类、静态代码块等方式实现饿汉式,通过非线程安全、同步方法、同步代码块、双重检查锁定和静态内部类等方式实现懒汉式。文章还对比了各种实现方式的优缺点,帮助读者在实际项目中做出更好的设计决策。
22 0
|
9天前
|
设计模式 传感器 运维
Harmony设计模式-单例模式
Harmony设计模式-单例模式
31 0