Java设计模式之单例模式深入探索

目录
  • 什么是设计模式?
  • 单例模式是什么?
  • 单例模式设计的原则是什么?
  • Java实现单例模式的5种方式?
    • 懒汉
    • 饿汉
    • 静态内部类
    • 双重校验锁DCL(Double Check Lock)
    • 枚举(num)
  • 小结

❤️‍您好,我是贾斯汀,今天来聊一聊单例模式!❤️‍

什么是设计模式?

百科:

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

设计模式是软件行业的通用的设计标准,在Java同样通用,主要有23种设计模式如下:

有的小伙伴可能会问,这么多,学得完吗?

答:不好意思,不要太自信了,一般人还真学不完,不过一些常用的设计模式,例如上图中标红的单例模式工厂模式代理模式等设计模式,还是需要花些时间和精力去多多了解一下,相信会对自己在程序设计或写代码时有很大的帮助。

本文主要来聊一聊设计模式中创建型的单例模式,进入正文~

单例模式是什么?

学习Java的小伙伴,相信都写过Class类吧,创建某个类实例化对象的核心是new MyClass()来实现,如果没有任何设计规范,在日常开发写代码时,如果实例被用的地方很多,每次调用的时候都通过new MyClass()得到实例化对象,代码重复而且频繁的创建对象还影响性能,而有些场景我们只需要提供该类的一个实例即可,例如平时比较常见的线程池、日志对象、缓存等,一般只需要确保有一个实例即可,这种确保某个类只有一个实例并且能够类自身提供自动创建实例化对象的设计模式即称为单例模式

单例模式设计的原则是什么?

  • 构造方法私有化:既然是单例,就不能将类的构造函数暴露在外面,因此需要重写构造函数为私有化;
  • 要考虑线程安全:多线程环境下,要确保不会构造出多个实例对象。

Java实现单例模式的5种方式?

关于Java实现单例模式的有几种方式,网上有很多说法,有5种、6种甚至7种实现方式,本文出于单例模式设计的两个主要原则构造方法私有化要考虑线程安全,不考虑线程安全的其他实现方式没有任何意义,主要有5种实现方式:

懒汉

使用懒汉式写法,主要是通过synchronized修饰实例化方法getInstance,保证了线程安全,并且只有调用getInstance时才初始化,顾此得名懒汉。
懒汉写法1:

/**
 * 单例模式之懒汉写法1
 */
public class Singleton {
    private static Singleton instance = null;
    private Singleton(){}
    public synchronized static Singleton getInstance(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉写法2:
该写法等价于写法1,原因在于关键字synchronized的灵活运用,放在方法上修饰,加锁的对象是Singleton,等效于将synchronized移到方法内部作为一个同步块,并通过括号中的Singleton.class显示指定锁对象,效果是一样的。

/**
 * 单例模式之懒汉写法2
 */
public class Singleton {
    private static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        synchronized(Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

饿汉

饿汉写法,只需要定义一个static静态变量instance = new Singleton(),简单的理解为在类加载时,也会完成单例对象的实例化工作。

/**
 * 单例模式之饿汉
 */
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}

细心的小伙伴会发现该过程并没有使用到synchronized关键字,那会不会线程不安全呢?答案是,不会,如果你大概了解过Java虚拟机即JVM(Java Virtual Machine),那你可能知道类加载过程为:加载 -> 验证 ->解析 ->初始化,而初始化阶段是执行类构造器<clinit>()方法的过程,<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合成产生的。
《深入理解Java虚拟机》类加载机制章节部分说明:

虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时如初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,知道活动线程执行<clinit>()方法完毕。

静态内部类

静态内部类这种方式,其实就是在类的内部创建一个static SingletonInner静态内部类,然后在静态内部类的内部再定义一个static final修饰的静态常量INSTANCE = new Singleton(),同样static修饰的SingletonInner静态内部类,会在JVM加载类时完成类的初始化并完成自己定义的静态常量单例实例化过程。

/**
 * 单例模式之静态内部类
 */
public class Singleton {
    private static class SingletonInner{
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton(){}
    public static Singleton getInstance(){
        return SingletonInner.INSTANCE;
    }
}

双重校验锁DCL(Double Check Lock)

DCL写法,其实与单例模式之懒汉写法2区别在于,synchronized同步块外面再套一层判断,并且使用了能确保线程安全核心volatile关键字修饰instance,表明单例变量是内存共享的,能够保证在多线程环境下的即时可见性

/**
 * 单例模式之双重校验锁DCL
 */
public class Singleton {
    private volatile static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if ( instance  == null ){
            synchronized (Singleton.class){
                if (instance  == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

枚举(num)

枚举方式很容易被大家给忽略掉了,但这种方式我觉得是最简单且又友好的一种推荐创建单例的方式,通过enum修饰Singleton单例类,仅需定义一个INSTANCE,然后在静态方法实例化方法getInstance中直接返回INSTANCE即可。

/**
 * 单例模式之枚举
 */
public enum Singleton {
    INSTANCE;
    public static Singleton getInstance(){
        return INSTANCE;
    }
}

小结

设计模式之单例模式,看似挺简单,其实还涉及了枚举enum、同步锁synchronized、JVM类加载机制、多线程volatile关键字的使用等Java的N个知识点。

本文提到的单例模式之懒饿内双枚5种方式,你学废了吗?

最后,学完希望你能熟悉的手写出任意一种实现单例模式的方式,并且对每一种写法是如何保证线程安全的原理也能够略知三四,祝你学习进步、工作顺利。

到此这篇关于Java设计模式之单例模式深入探索的文章就介绍到这了,更多相关Java 设计模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JAVA设计模式---单例模式你知道吗

    目录 单例模式的介绍 单例模式实现的八种方式 饿汉式 静态常量 静态代码块 懒汉式 线程不安全的写法 线程安全,同步锁-效率低,不推荐 线程安全,同步代码块-无法解决线程安全问题,不推荐 双重检查-解决线程安全和懒加载问题–推荐使用 静态内部类-可以实现懒加载,线程安全,推荐使用 枚举 单例模式注意事项 总结 单例模式的介绍 单例模式实现的八种方式 饿汉式 静态常量 步骤: 1.构造器私有化(防止new) 2.类的内部创建对象 3.向外暴露一个静态的公共方法-getInstance //饿汉式静

  • Java单例模式分析

    目录 单例模式 为什么要用单例 单例的关键点 几种写法 懒汉式 饿汉式 静态内部类写法 枚举单例 容器实现单例 参考 总结 单例模式 为什么要用单例 确保某个类只有一个对象,常用于访问数据库操作,服务的配置文件等. 单例的关键点 1.默认构造函数为private,复制构造函数和复制赋值函数也要private或=delete禁用.(做到无法被外部其他对象构造) 2.通过一个静态方法或枚举返回单例类对象. 3.确保多线程的环境下,单例类对象只有一个. 几种写法 本文主要介绍C++的懒汉式和饿汉式写法

  • Java中单例模式的七种写法示例

    目录 前言 1.饿汉式(线程安全)⭐ 2.懒汉式(线程不安全)⭐ 3.懒汉式(加锁) 4.懒汉式(双重校验锁)⭐ 5.单例模式(静态内部类) 6.单例模式(CAS) 7.单例模式(枚举) 总结 前言 大家好,我是三乙己.考上大家一考:"单例模式的单例,怎样写的?" "不就是构造方法私有化么?" "对呀对呀!--单例模式有七种写法,你知道么?" 言归正传-- 单例模式(Singleton Pattern)可以说是最简单的设计模式了. 用一个成语来形

  • Java单例模式的6种实现方式详解

    目录 为什么使用单例模式 使用单例模式需要注意的关键点 单例模式的几种写法 1. 饿汉式 2. 懒汉式 3. DCL(Double CheckLock)实现单例 4. 静态内部类 5. 枚举单例 6. 容器实现单例 总结 为什么使用单例模式 需要确保某个类只要一个对象,或创建一个类需要消耗的资源过多,如访问IO和数据库操作等,这时就需要考虑使用单例模式了. 使用单例模式需要注意的关键点 将构造函数访问修饰符设置为private 通过一个静态方法或者枚举返回单例类对象 确保单例类的对象有且只有

  • Java设计模式系列之深入浅出单例模式

    目录 前言 饿汉式 懒汉式 线程安全问题 volatile的作用 总结 前言 我不知道大家工作或者面试时候遇到过单例模式没,面试的话我记得我当时在17年第一次实习的时候,就遇到了单例模式,面试官是我后来的leader,当时就让我手写单例,我记得我就写出了饿汉式,懒汉式,但是并没说出懒汉和饿汉的区别,当时他给我一通解释我才知道了其中的奥秘. 写这篇文章之前我刻意的在我手上的项目里面去找了找,我发现单例在每个项目里面都有运用到,而且我后面所说的几种实现还基本上都涉及了,还挺有意思的. 开篇我就给大家

  • Java设计模式之单例模式深入探索

    目录 什么是设计模式? 单例模式是什么? 单例模式设计的原则是什么? Java实现单例模式的5种方式? 懒汉 饿汉 静态内部类 双重校验锁DCL(Double Check Lock) 枚举(num) 小结 ❤️‍您好,我是贾斯汀,今天来聊一聊单例模式!❤️‍ 什么是设计模式? 百科: 设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结. 设计模式是软件行业的通用的设计标准,在Java同样通用,主要有23种设计模式如下: 有的小伙伴可能会问,这么多,学得完吗? 答:不好意思

  • java设计模式之单例模式的详解及优点

    java设计模式之单例模式 定义:如果一个类始终只能创建一个实例,那么这个类被称为单例类,这种设计模式被称为单例模式. Spring框架里面可以将所有生成的bean对象都设置为单例模式,只需要在配置Bean实例时指定scope="singleton"即可,或者不做配置默认即为单例模式. 我们可以创建一个小的Demo来演示单例模式的实现,只需要保证该类只能创建一个实例,我们可以用权限修饰符private修饰该类的构造器. 提供一个创建该类的接口,该接口只能用static修饰,类里面创建一

  • Java设计模式之单例模式实例分析

    本文实例讲述了Java设计模式之单例模式.分享给大家供大家参考,具体如下: 单例模式:(Singleton Pattern)是一个比较简单的模式,其定义如下: Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例) 单例模式,很简单的一个模式.其实在android开发中,很多地方都会用到单例模式,比如某些工具类.Json数

  • Java设计模式之单例模式实例详解【懒汉式与饿汉式】

    本文实例讲述了Java设计模式之单例模式.分享给大家供大家参考,具体如下: 单例模式就是产生一个对象实例,供外外部访问. 它的应用场景就是在这个类在全局真资源需要统一访问,否则会造成混乱时,才有必要设计成单例. 懒汉式,就是在使用这个对象时,才去查看这个对象是否创建,如果没创建就马上创建,如果已经创建,就返回这个实例. 饿汉式,在加载这个类的时候就先创建好一个对象实例,等待调用. 两者的优缺点也能猜到,使用懒汉式,在反应速度上肯定要比饿汉式慢. 但是这个对象如果不被调用,那就节省了cpu和内存资

  • java 设计模式之单例模式

    java  设计模式之单例模式 前言: 在软件开发过程中常会有一些对象我们只需要一个,如:线程池(threadpool).缓存(cache).对话框.偏好设置等.这些对象如果制造出多个实例的话可能会导致一些不必要的麻烦,如:程序行为异常.资源使用过量等.这时单例模式就可以确保一个类只有一个实例,并提供全局访问点.下面是从简单的单例类来探讨该用何种方法实现单例模式. /** * 最经典的单例类 */ public class Singleton { // 设置成静态变量来记录Singleton的唯

  • 全面解析Java设计模式之单例模式

    本文实例为大家分享了Java设计模式之单例模式的具体代码,供大家参考,具体内容如下 概念: 单例模式:一个类中只有一个实例. 一个类有且仅有一个实例,并且提供了一个全局的访问点. 使用该模式的起因: 当我们在浏览网站时,有些网站会显示"当前在线人数".通常,实现这个功能的办法是将登陆的每一个IP存储在一个内存.文件或者数据库中,每多一个IP,就实现"+1".一般就是用一个方法,比如add(),实现"+1"的功能,比如用"update&q

  • Java设计模式之单例模式简介

    一.饿汉式(静态常量) public class Face { private static final Face instance = new Face(); static Face getInstance() { return instance; } private Face() { } } 优点:这种写法比较简单,就是在类装载的时候就完成实例化.避免了线程同步问题. 缺点:在类装载的时候就完成实例化,没有懒加载的效果.如果从始至终从未使用过这个实例,则会造成内存的浪费. 二.饿汉式(静态代

  • Java设计模式之单例模式示例详解

    目录 0.概述 1.饿汉式 1.1 饿汉式单例实现 1.2 破坏单例的几种情况 1.3 预防单例的破坏 2.枚举饿汉式 2.1 枚举单例实现 2.2 破坏单例 3.懒汉式 4.双检锁懒汉式 5.内部类懒汉式 6.JDK中单例的体现 0.概述 为什么要使用单例模式? 在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池.缓存.对话框.注册表.日志对象.充当打印机.显卡等设备驱动程序的对象.事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常.

  • C++和java设计模式之单例模式

    单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点.其构造过程由自身完成,可以将构造方法定义为private型的,这样外界就只能通过定义的静态的函数Instance()构造实例,这个函数的目的就是返回一个类的实例,在此方法中去做是否有实例化的判断.客户端不再考虑是否需要去实例化的问题,把这些都交给了单例类自身.通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法,就是让类自身负责保存它的唯一实例.这个类可以保证没有其他实例可

  • Java设计模式之单例模式详解

    单例模式是非常常见的设计模式,其含义也很简单,一个类给外部提供一个唯一的实例.下文所有的代码均在github 源码整个项目不仅仅有设计模式,还有其他JavaSE知识点,欢迎Star,Fork 单例模式的UML图 单例模式的关键点 通过上面的UML图,我们可以看出单例模式的特点如下: 1.构造器是私有的,不允许外部的类调用构造器 2.提供一个供外部访问的方法,该方法返回单例类的实例 如何实现单例模式 上面已经给出了单例模式的关键点,我们的实现只需要满足上面2点即可.但是正因为单例模式的实现方式比较

随机推荐