23种设计模式第一章:单例模式

news2024/12/24 11:27:29

这里写自定义目录标题

  • 一 单例模式
    • 1 静态常量饿汉式
    • 2 静态代码块饿汉式
    • 3 线程不安全懒汉式
    • 4 线程安全懒汉式
      • 线程安全,同步方法
      • 线程安全,同步代码块
    • 5 doubleCheck(双重检查,推荐使用)
    • 6 静态内部类
    • 7 枚举

一 单例模式

单例模式就是保证在某个软件系统中,对某个类只存在一个对象实例,并且·该类只存在一个取得其对象实例的方法(静态方法)

  • 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使 用单例模式可以提高系统性能
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
  • -单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级 对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)

1 静态常量饿汉式

在这里插入图片描述

public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton instance=Singleton.getInstance();
        Singleton instance2=Singleton.getInstance();
       //比较地址的值
        System.out.println(instance2==instance);
        //比较两者的HashCode
        System.out.println("instance2.hashcode:"+instance2.hashCode());
        System.out.println("instance.hashCode:"+instance.hashCode());
    }
}
//饿汉式:静态变量
class Singleton{
    //1.构造器私有化,外部不能new出来
    private   Singleton(){

    }
    //2.本类内部创建一个对象实例
    private final static Singleton instance=new Singleton();

    //3 提供一个公有的静态对象,返回实例对象
    public static Singleton getInstance(){
        return  instance;
    }
}

运行结果可以看出来,hashcode的值是一样的,说明这两个对象实例实际上是一个对象实例
在这里插入图片描述
优点:

  • 写法比较简单,在类装载时候就完成了实例化,避免了线程同步的问题

缺点:

  • 在类加载的时候就完成实例化,没有达到懒加载(Lazy loading)的效果,如果这个实例从始至终都没有被调用,就会造成内存的浪费
  • 虽然采用classloder机制避免了多线程的同步问题,但是导致类装载的方式有很多种,不确定是否因为其他方式导致类装载

总结:

  • 这种单例模式可以用,但是会造成内存的浪费

2 静态代码块饿汉式

//饿汉式:静态代码块的方式

public class Singleton{
    //1.构造器私有化,外部不能new出来
    private   Singleton(){


    }
    //2.本类内部创建一个对象实例
    private  static Singleton instance;

    static {
        instance=new Singleton();
    }

    //3 提供一个公有的静态对象,返回实例对象
    public static Singleton getInstance(){
        return  instance;
    }
}

优点:类实例化的过程,放在了静态代码块中执行,静态代码块也是在类装载的时候执行的
结论:会造成内存浪费

  • java.lang.RunTime是最经典的饿汉式,单例模式

3 线程不安全懒汉式

功能子类,本类内部创建对象实例

package com01.xyt;

public class Singleton {
    // 构造器私有化,外部不能new
    private static Singleton instance;
    //本类内部创造对象实例
    private   Singleton(){

    }

    // 提供一个公有的静态方法,使用到该方法时,才创建instance,懒汉,不用不创建
    public static Singleton getInstance(){
        if (instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}

优点:

  • 确实起到了LazyLoading的效果,用到才创建,用不到不创建,只能在单线程条件下用
  • 多线程下,一个线程进入了if判断语句块,还没来得及向下执行,另一个线程也通过了判断块,就会创造出多个实例,存在风险
  • 实际开发时候,不要采用这种方式,存在风险

4 线程安全懒汉式

线程安全,同步方法

public class Singleton {
    // 构造器私有化,外部不能new
    private static Singleton instance;
    //本类内部创造对象实例
    private   Singleton(){

    }

    // 提供一个静态的公有方法,使用到该方法时,才创建instance,
    // 懒汉,不用不创建
    //get方法,得到一个值
    //加入同步关键字,多个线程排队
    public static synchronized Singleton getInstance(){
        if (instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}

分析:

  • 解决了线程不安全的问题,但是效率太低,每个线程想要获得类的实例的时候,执行getInstance()方法都要同步
  • 但其实这个方法执行一次实例化代码就够了,后面想获得该类实例,直接return就行,方法同步效率太低,用了同步机制来解决
  • 重量级同步关键字,sythonized

线程安全,同步代码块

package com01.xyt;

public class Singleton {
    // 构造器私有化,外部不能new
    private static Singleton singleton;
    //本类内部创造对象实例
    private   Singleton(){

    }

    // 提供一个静态的公有方法,使用到该方法时,才创建instance,
    // 懒汉,不用不创建
    //get方法,得到一个值
    //加入同步关键字,多个线程排队
    public static  Singleton getInstance(){
        if (singleton==null){
            synchronized (Singleton.class){
                singleton=new Singleton();
            }
        }
        return singleton;
    }
}

说明:

  • 这种方法实际上是一种伪同步,实际上并没有起到线程同步的作用
  • 容易导致多个线程进入if判断,从而产生多个实例,效率低,实际开发中不能用

5 doubleCheck(双重检查,推荐使用)

package com01.xyt;

public class Singleton {
    // 构造器私有化,外部不能new
    private static volatile Singleton instance;
    //本类内部创造对象实例
    private   Singleton(){

    }

    /**
     * 提供了一个静态的公有方法去,加入双重检查代码,解决线程安全与懒加载问题
     * 保证效率,推荐使用
     * @return
     */

    public static  Singleton getInstance(){
        //A B,控制进一个
        if (instance==null){
            //对Singleton进行同步
            synchronized (Singleton.class){
                //A进来,B进不去
                if (instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

说明:

  • 两个if判断,一个不够用
  • 解决了线程安全与效率的问题,因此推荐使用
  • 用了volatile,一种轻量级主存
  • Double-Check概念是线程开发中经常使用到的,如图所示,进行了两次if(Singleton== null)的检查,可以保证线程安全
  • 实例代码只执行一次,后面再访问时,判断if(singleton==null),直接return实例化对象
  • 线程安全,延迟加载,效率较高

6 静态内部类

package com01.xyt;

public class Singleton {
    // 构造器私有化,外部不能new
    private static volatile Singleton instance;
    //本类内部创造对象实例
    private   Singleton(){

    }
     //JVM装载内部类是安全的
    //写一个静态内部类,这个类中有一个静态属性Singleton
    private static class SingletonInstance{
        private static final Singleton INSTANCE=new Singleton();
    }
    //提供一个静态的公有方法,直接返回成员变量
    public static synchronized Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }

}

说明:

  • 外部类被装载时候,内部类不一定被装载
  • 装载时候,线程是安全的,采用类装载机制,确保初始化实例时候,只有一个线程
  • 静态内部类方法在Singleton类被装载时,并不会立即实例化,而是在需要实例化时候,调用getInstance方法,装载SingletonInstance类,从而完成Singleton的实例化
  • 类的静态属性只会在第一次进行类的加载时候进行初始化,JVM帮助我们保证了线程的安全性,一次只能进入一个线程
  • 避免了线程不安全,静态内部类实现延迟加载,效率高
  • 用到静态实例才会加载

7 枚举

public class SingletonTest3 {
    public static void main(String[] args) {
        Singleton instance= Singleton.INSTANCE;
        Singleton instance2= Singleton.INSTANCE;
        //比较地址的值
        System.out.println(instance2==instance);
        //比较两者的HashCode
        System.out.println("instance2.hashcode:"+instance2.hashCode());
        System.out.println("instance.hashCode:"+instance.hashCode());
        instance.sayOK();
    }
}
enum Singleton{
    INSTANCE;//属性
    public void sayOK(){
        System.out.println("-------OK");
    }
}

说明:

  • 枚举避免多线程同步问题,同时防止反序列化重新创建新的对象
  • 推荐使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

K8s 安全是云安全的未来

导语 到 2025 年,保护 Kubernetes (K8s) 将被认为是云安全最重要的方面。 在最成功的组织中,CTO 和 CISO 已经意识到 Kubernetes 安全的重要性。 但是,虽然 Kubernetes 已经占 CTO 云支出的很大一部分,但 CISO 仍然有所落后。 大…

基于web的课程重难点掌握情况分析系统

1.系统登录:系统登录是用户访问系统的路口,设计了系统登录界面,包括用户名、密码和验证码,然后对登录进来的用户判断身份信息,判断是管理员用户还是普通用户。 2.系统用户管理:不管是…

19.考虑柔性负荷的综合能源系统日前优化调度模型

说明书 MATLAB代码:考虑柔性负荷的综合能源系统日前优化调度模型 关键词:柔性负荷 需求响应 综合需求响应 日前优化调度 综合能源系统 参考文档:《考虑用户侧柔性负荷的社区综合能源系统日前优化调度》参考柔性负荷和基础模型部分&#xf…

脑电信号特征提取方法与应用

前言 脑电图(EEG)信号在理解与脑功能和脑相关疾病的电活动方面发挥着重要作用。典型的脑电信号分析流程如下:(1)数据采集;(2)数据预处理;(3)特征提取;(4)特征选择;(5)模型训练与分类;(6)性能评估。当信号分…

SpringClouid学习笔记(正在更新中...)

目录 SpringCloud1、微服务1.1、定义1.2、特性单体应用微服务应用 1.3、微服务架构演变(RPC)1.4、微服务解决方案 2、SpringCloud2.1、什么是SpringCloud官方定义DemoSpringCloud版本和SpringBoot版本选择 3、环境搭建环境说明构建方式开始构建 4、服务注…

全注解下的SpringIoc 续3-属性文件的使用

在Spring Boot中使用属性文件,可以采用默认的application.properties文件,也可以使用自定义的配置文件,下面让我们一起来看看这两个的使用。 使用默认的application.properties文件 这个配置文件是Spring Boot默认会加载的,所以…

自动抓取QQ好友列表?Windows UIA教你轻松实现

目录:导读 引言 选择Windows UIA框架进行自动化测试的原因 查找窗口 读取QQ软件的好友列表 结语 引言 每个使用QQ的人都有自己的好友列表,但是如果你想要查看所有好友信息,手动一个个点击会非常浪费时间。那么有没有什么快速获取好友列…

【openGauss实战12】表空间管理

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

【总线】IIC学习笔记

【总线】IIC学习笔记 参考链接IIC总线介绍IIC总线时序1.空闲信号2. 启动信号与停止信号3.数据的有效性4.应答信号5.七位地址传输 IIC读写过程(AT24C02举例)IIC读过程IIC写过程 正点原子IIC驱动问题1、IIC停止信号问题2、IIC-AT24C02的器件地址发送的疑惑…

OJ搭建配置 功能速查手册

服务器配置 腾讯云 2H4G 5M 60GB 轻量应用服务器 承载大约 200~400人使用,经过压力测试,评测并发速度可满足130人左右的在线比赛。 系统镜像选 Ubuntu 22.04 LTS。 用户管理 一、批量导入(从方便管理角度建议以 学生姓名 作为 用户名 &am…

网络安全之黄金票据,白银票据

前言:今天来给大家讲讲黄金票据和白银票据Kerberos认证#金票Golden ticket# 原理#伪造金票的场景和所需条件#利用方式#银票SILVER TICKET# 原理#伪造银票所需条件#金票和银票的区别# 获取的权限不同#认证流程不同#加密方式不同# 前言:今天来给大家讲讲黄…

Unity 3D 学习笔记(1)

文章目录 1.Unity 3D 概述2.Unity的安装过程3.Unity 3D 的项目管理4.Unity 3D 中的场景5.Unity 3D 的界面组成 1.Unity 3D 概述 Unity 3D简介:Unity 3D是虚拟现实行业中使用率较高的一款开发引擎,由Unity Technology公司开发。通过Unity,开发…

手动实现 Spring 底层机制【初始化 IOC容器+依赖注入+BeanPostProcessor 机制+AOP】

目录 手动实现 Spring 底层机制【初始化 IOC容器依赖注入BeanPostProcessor 机制AOP】 前面我们实际上已经用代码简单实现了 代码演示使用框架 创建一个maven项目 创建UserAction类 创建UserDao类 创建UserService类 创建beans.xml 说明 创建AppMain类 运行效果 如图…

《汇编语言》- 读书笔记 - 第2章-寄存器

《汇编语言》- 读书笔记 - 第2章-寄存器 2.0 8086CPU 寄存器段地址:偏移地址 2.1 通用寄存器2.2 字在寄存器中的存储2.3 几条汇编指令表2.1汇编指令举例表2.2 程序段中指令的执行情况之一问题 2.1表2.3 程序段中指令的执行情况之二问题 2.2 2.4 物理地址2.5 16位结构的CPU2.6 8…

数据埋点1

文章目录 1 什么是数据埋点2 为什么需要数据埋点3 数据埋点能采集哪些用户数据4 数据埋点的分类及方式5 主流的数据上报技术5.1 客户端上报5.2 服务端获取 1 什么是数据埋点 互联网的海量数据是通过数据埋点技术采集用户行为数据而产生的,用户行为数据采集及上报流…

我又不当程序员还要学Python吗?人工智能AI的出现我知道,我错了

Python(可读音:派森) 时代要淘汰你,连招呼都不会打! 这句话近些年我们常在媒体上听到,有点残酷,但却又很现实。 最近,人工智能AI技术火爆全网,而且它所表现出来的“超…

浅谈Spring中的BeanFactory与FactoryBean

前言 理解FactoryBean是非常非常有必要的,因为在Spring中FactoryBean最为典型的一个应用就是用来创建AOP的代理对象,不仅如此,而且对理解Mybatis核心源码也非常有帮助!如果甘愿crud,做个快乐的码农,那我就哦…

Springcloud--docker快速入门

认识docker docker相关操作 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中,依赖的组件非常多,不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…

『Linux』第九讲:Linux多线程详解(三)_ 线程互斥 | 线程同步

「前言」文章是关于Linux多线程方面的知识,上一篇是 Linux多线程详解(二),今天这篇是 Linux多线程详解(三),内容大致是线程互斥与线程同步,讲解下面开始! 「归属专栏」Li…

剑指 Offer 54. 二叉搜索树的第k大节点【37】

难度等级:容易 上一篇算法: 226. 翻转二叉树【58】 力扣此题地址: 剑指 Offer 54. 二叉搜索树的第k大节点 - 力扣(Leetcode) 1.题目:剑指 Offer 54. 二叉搜索树的第k大节点 给定一棵二叉搜索树&#xff0c…