设计模式——单例模式详解

简介: 设计模式——单例模式详解

什么是单例模式


单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。在程序中多次使用同一个对象且作用相同的时候,为了防止频繁的创建对象,单例模式可以让程序在内存中创建一个对象,让所有的调用者都共享这一单例对象


单例的实现主要是通过以下两个步骤:


1.将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;

2.在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。


单例模式类型


饿汉式:在类加载的时候已经创建好该单例对象。

懒汉式:在需要使用对象的时候才会去创建对象


单例模式的实现


饿汉式


步骤如下:

1)构造器私有化(防止new )

2)类的内部创建对象

3)向外暴露一个静态的公共方法。getInstance

4)代码实现:

class Singleton {
    //1.构造器私有化,只能在内部new对象
    private Singleton(){
    }
    //2.内部实例化
    private final static Singleton instance =new Singleton();
    //3.提供get方法供外部使用,返回实例对象
    public static Singleton getInstance(){
        return instance;
    }
}


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

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


懒汉式


class Singleton{
    private Singleton(){
    }
    private static Singleton instance;
    public static synchronized Singleton getInstance(){
        if(instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}


效率低

比如当单例创建好之后,此时不会存在任何线程安全问题,但是每次访问仍然要加锁。导致效率低下。


双重检查


class Singleton{
    private Singleton(){}
    //volatile确保INSTANCE每次均在主内存中读取,这样虽然会牺牲一点效率,但也无伤大雅。(JDK1.5之后)
    private static volatile Singleton instance;
    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 Singleton(){
    }
    private static class SingletonInstance{
        private static final Singleton INSTANCE =new Singleton();
    }
    public static synchronized Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }
}


静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

推荐使用


关于静态内部类又是如何实现线程安全的呢?见:静态内部类利用了类的加载机制实现多线程安全


枚举


enum Singleton{
    INSTANCE;
}


枚举是饿汉式的

它也是静态成员变量,在类加载的时候就初始化完毕了。

问:反射能破坏其单例吗?

答:不能。反射在通过Newinstance创建对象会检查该类是否是枚举类型,是的话就反射失败

推荐使用


单例模式在JDK中的体现


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


2322923a0df34f9db3b8d1acb33afe2d.png

单例模式存在的问题


1.单例对OOP特性的支持不友好OOP的四大特性是封装、抽象、继承、多态。

2.单例会隐藏类之间的依赖关系

由于单例类不需要创建,只要调用函数就能产生,所以如果代码特别复杂,那么调用关系就会比较隐蔽,在阅读代码时,就需要仔细查看每个函数的代码实现,才能知道这个类到底依赖了哪些单例类


3.单例对代码的扩展性不友好


比如一开始对于数据库连接池只需要一个。

而后期某些sql查询比较慢,执行的时候长期占用数据库连接池的资源,导致其他查询无法响应。

为了解决这个问题,就希望将慢sql和其他sql隔离开执行,这样就需要要创建两个数据库连接池,慢sq|独享一个连接池。但是已经将数据库连接设置成单例了。显然无法应对这样的需求变更

所以,数据库连接池、线程池这类的资源池,最好还是不要设计成单例类。实际上,一些开源的数据库连接池、线程池也确实没有设计成单例类。


4.单例不支持有参数的构造函数


比如我们创建一个连接池的单例对象,我们没法通过参数来指定连接池的大小。

解决思路是:将参数放到另外一个全局变量中。具体的代码实现如下。Config 是一个存储了paramA和 paramB值的全局变量。里面的值既可以像下面的代码那样通过静态常量来定义,也可以从配置文件中加载得到。实际上,这种方式是最值得推荐的.

相关文章
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
30 2
|
8天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
14 2
|
22天前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
29 4
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
14天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
19 1
|
22天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
23 0
|
2月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
2月前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy<T>` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
47 1
|
2月前
|
设计模式 缓存 数据库连接
探索PHP中的设计模式:单例模式的实现与应用
在PHP开发中,设计模式是提高代码可复用性、可维护性和扩展性的重要工具。本文将深入探讨单例模式(Singleton Pattern)的基本概念、在PHP中的实现方式以及实际应用场景。单例模式确保一个类仅有一个实例,并提供全局访问点。通过具体代码示例和详细解释,我们将展示如何在PHP项目中有效利用单例模式来解决实际问题,提升开发效率和应用性能。