设计模式——单例模式

2023-05-16

设计模式包括三大类

创建型模式(主要用来建立对象)

    单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式

结构型模式

    适配器模式 桥接模式 装饰模式 组合模式 外观模式 享元模式 代理模式

行为型模式

    模板方法模式 命令模式 迭代器模式 观察者模式 中介者模式 备忘录模式 解释器模式  状态模式 策略模式 职责连模式 访问者模式

首先来说单例模式

核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

单例模式的常见应用场景:

Windows的任务管理器以及回收站

项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取

网站的计数器,也是采用单例模式实现。否则难以同步。

应用程序的日志应用,一般都采用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加

数据库连接池的设计一般采用单例模式,因为数据库连接是一种数据库资源

操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统

Application也是典型的单例应用

Spring中每个bean默认是单例(singleton)的

在SpringMVC/Struts1框架中,控制器对象也是单例的

 

单例模式的优点:

由于单例模式只生成一个实例,减少了系统性能开支,当一个对象的产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻扎内存的方式来解决

单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理

 

常见的五种单例模式及实现方式:

主要::

    饿汉式:(线程安全,效率高,但是,不能延时加载)

    懒汉式:(线程安全,效率相对不高,但是,可以延时加载)

其他:

    双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)

    静态内部类式 (线程安全,效率高,可以延时加载)

    枚举单例(线程安全,效率高,不能延时加载)

 

饿汉式实现:

1.构造方法私有

2.定义一个私有静态变量,并通过私有构造方法创建对象

3.定义一个public的静态方法,返回静态变量的值

public class SingletonHungry {

    //构造方法私有化
    private SingletonHungry (){}

    //定义一个私有静态变量,获取私有构造方法 饿汉式 很饥饿 类初始化时立即加载对象(没有延时加载的优势)
    //类加载的时候 是线程安全的 如果没有使用该类 但已经在初始化的时候加载了 浪费资源 饿汉式的缺点
    private static SingletonHungry instance= new SingletonHungry ();

    //定义一个public方法,返回静态变量的值 方法没有同步效率高
    public static SingletonHungry getInstance(){

        return instance;
    }
}

饿汉式单例模式中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此可以省略synchronized关键字

类初始化的时候就会创建对象,如果未使用该对象 会造成资源的浪费 真实由于创建对象时机很快 所以叫饿汉式

调用效率很频繁的时候用饿汉式  类创建对象的成本很高的话用懒汉式

 

懒汉式(单例对象延迟加载)

实现:

1.构造方法私有化

2.定义一个私有静态变量

3.定义一个public的是static方法,在该方法被调用时再去创建对象并赋值给私有静态变量 并返回该私有变量

public class SingletonLazy {

    //构造方法私有化
    private SingletonLazy(){}

    //定义一个私有静态变量,不初始化这个对象(延时加载,用的时候在创建)
    private static SingletonLazy instance;
 
    //定义一个public方法,在该方法被调用时再去创建对象并赋值给私有静态变量 并返回该变量 调用时才创建对象,所以需要加同步
    public static synchronized SingletonLazy getInstance(){

        if(null == instance){
            instance= new SingletonLazy ();
        }
        return instance;
    }
}

2.定义

要点:延迟加载,在真正需要的时候才加载

缺点:资源利用率高了。但是,每次调用getInstance()方法都要同步,并发效率低

为了综合弥补懒汉和饿汉的缺陷,讲一下另外 一些单例模式

 

双重检测锁实现

这个模式将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步(对懒汉式缺点的优化),只在第一次访问的时候才同步,以后访问就不用进行同步

代码实现:

public class SingletonDoubbleKey {

    //构造方法私有化
    private SingletonDoubbleKey (){}
 
    //定义一个私有静态变量  volatile防止指令重排
    private static volatile SingletonDoubbleKey instance;
 
    public static  SingletonDoubbleKey getInstance(){

        if(null == instance){
            synchronized(SingletonDoubbleKey.class){//将synchronized放到if里
                if(null == instance){//双重检测
                    instance = new SingletonDoubbleKey();                    
                }
            }
           
        }

        return instance;
    }
}

由于编译器优化原因和JVM底层内部模型原因,偶尔会出现问题,不建议使用。所以了解即可

 

静态内部类实现方式(也是一种懒加载方式)

实现代码:

public class SingletonDemo4 {

    //构造方法私有化
    private SingletonDemo4(){}

    //定义私有静态内部类
    private static class Singleton{

        private static final SingletonDemo4 instance = new SingletonDemo4();
    }
 
    public static  SingletonDemo4 getInstance(){

        return Singleton.instance;
    }
}

要点:

外部类没有static属性,不会像饿汉式那样立即加载对象

只有真正调用getInstance()方法,才会加载静态内部类。加载类时是线程安全的。instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全

兼备了并发高效调用和延迟加载的优势

 

使用枚举实现单例模式

代码实现:

public enum SingletonDemo5 {

    //定义一个枚举的元素,它代表了一个singleton的一个实例
    INSTANCE;

    /**
    * 单例可以有自己的操作
    */
    public void operation(){
    //功能处理
    }
}

优点:

实现简单

枚举本身就是单例模式。由JVM从根本上提供保证,避免通过反射和反序列化的漏洞

缺点:

无延迟加载

 

总结:

单例模式实现

主要:

饿汉式(线程安全,调用效率高。但是,不能延迟加载)

懒汉式(线程安全,调用效率不高,同步方法需要等待,可以延迟加载)

其他:

双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不推荐使用)

静态内部类式(线程安全,调用效率高,而且可以延迟加载)

枚举式(线程安全,效率高,不可以延迟加载 可以天然的防止反射和反序列化漏洞)

 

如何选用

单例对象占用资源少,不需要延迟加载时

 枚举式好于饿汉式

单例对象占用资源大,需要延迟加载

静态内部类式好于懒汉式

 

原创不易:转载请标明出处:https://mp.csdn.net/postedit/80866450 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式——单例模式 的相关文章

  • zookeeper节点详解

    一 节点类型 persistent 持久节点 persistent sequential 持久序号节点 ephemeral 临时节点 ephemeral sequential 临时序号节点 1 persistent 持久节点 默认创建的节点
  • Zookeeper客户端详解

    zk常见客户端有三种 zookeeper原生Java APIZkClientApache curator 1 原生ZookeeperAPI lt dependency gt lt groupId gt org apache zookeepe
  • UILabel标签文字过长时的显示方式

    lineBreakMode xff1a 设置标签文字过长时的显示方式 label lineBreakMode 61 NSLineBreakByCharWrapping 以字符为显示单位显示 xff0c 后面部分省略不显示 label lin
  • error launching idea

    报错内容如下 解决方法 xff1a 如下图 idea 右击 gt 属性 gt 兼容性 gt 设置 gt 勾选 以管理员身份运行此程序 gt 应用 gt 确定
  • idea打开vue项目卡死问题解决

    解决方案 xff1a file gt settings gt File Types gt ActionScript gt as gt 给下面添加 node modules 然后 apply gt ok
  • Linux下载并安装rabbitmq-server-3.6.5-1.noarch.rpm

    目录 1 安装rabbitmq所需要的依赖包 2 下载安装包 3 安装服务命令 4 修改配置 5 启动rabbitmq 6 rabbitmq控制台安装 7 访问你的虚拟机 ip 15627 会出现下面的页面 用户名和密码都是 guest 8
  • nacos集群: code:503 msg: server is STARTING now, please try again later!

    在搭建nacos集群的时候 xff0c 集群启动成功的前提下 启动项目报如下错误 xff1a 解决方法 xff1a 1 cd 你nacos的bin目录 2 vim startup sh 3 在 JAVA OPT 61 34 JAVA OPT
  • yum安装rabbitmq的目录

    一般我们yum安装完rabbitmq后 xff0c 不知道安装到什么地方了 xff0c 其实是安装到下面的路径 usr lib rabbitmq lib 如下图所示 xff1a
  • Linux环境安装Redis

    下载地址 xff1a http download redis io releases 安装步骤 xff1a 1 安装gcc yum install gcc 2 把下载好的redis 4 0 14 tar gz xff08 选择你自己的版本
  • Redis主从环境搭建

    首先先搭建一个Redis xff1a 搭建方法 xff1a Linux环境安装redis 1 新建一个目录 xff0c 按照上述链接中的方法再次搭建一个redis 2 搭建完后 xff0c 修改从节点的redis conf文件 2 1 修改
  • Redis集群环境搭建

    一 下载redis xff08 此处我下载的是5 0 3版本 xff09 下载地址 xff1a http download redis io releases Linux命令下载 xff1a wget http download redis
  • Jvisualvm使用及添加Visual GC组件

    只要装了jdk xff0c 就会自带这个工具 xff0c 路径位置如下 xff1a JVisualvm添加Visual GC插件 动态观察各个年代GC情况 访问地址 xff1a https visualvm github io plugin
  • Spring源码编译Java: 找不到符号 InstrumentationSavingAgent

    报错如下 xff1a 解决 xff1a 将spring context gradle文件的 下面这一行 br optional project 34 spring instrument 34 br 修改为 br compile projec
  • RabbitMQ学习(六)——消息确认机制(Confirm模式)

    在上一篇文章中我们讲解了RabbitMQ中的AMQP事务来保证消息发送到Broker端 xff0c 同时我们可以在事务之间发送多条消息 xff08 即在channel txSelect 和channel txCommit 之间发送多条消息
  • zookeeper初识

    一 节点类型 persistent 持久节点 persistent sequential 持久序号节点 ephemeral 临时节点 ephemeral sequential 临时序号节点 1 persistent 持久节点 默认创建的节点
  • xmlns:dubbo=“http://dubbo.apache.org/schema/dubbo“报错

    请先看看你有没有加dubbo的maven依赖 xff0c 官网在做这个demo的时候并没有说要加maven依赖 xff0c 所以会xml中会报红 lt beans xmlns xsi 61 34 http www w3 org 2001 X
  • tomcat 8源码环境编译

    源码下载 下载地址 xff1a https tomcat apache org download 80 cgi 配置 1 解压下载好的源码包 apache tomcat 8 5 57 src zip 2 解压好后 xff0c 在解压后的目录
  • servlet配置文件解析

    1 配置 lt servlet gt xff08 以下代码均是web xml中的 xff09 lt servlet gt lt servlet name gt FirstServlet lt servlet name gt lt servl
  • 线程基础之—线程的创建

    线程创建分三类 1 继承Thread 43 run 启动 xff1a 创建子类对象 43 对象 start 2 实现Runnable 43 run 启动 xff1a 使用静态代理 1 gt 创建真实角色 2 gt 创建代理角色 Thread
  • 死锁

    一个死锁的代码 public class Demo public static void main String args Object g 61 new Object Object m 61 new Object Goods goods

随机推荐

  • 多线程之任务调度

    Timer定时器类 TimerTask任务类 通过java timer timetask xff1a xff08 Spring的任务的任务调度就是通过他们实现的 xff09 在这种实现方式中 xff0c Timer类实现的是类似于闹钟的功能
  • static关键字

    在类中 xff0c 用static声明的成员变量为静态成员变量 xff0c 或者叫做 xff1a 类属性 xff0c 类变量 它为该类的公用变量 xff0c 属于类 xff0c 被该类的所有实例共享 xff0c 在类被载入时被显示初始化对于
  • I/O流读写文件详解

    文件类 文件中路径的写法 xff1a 1 String filePath 61 34 C AAA a txt 34 第一个 表示转义字符 2 filePath 61 34 C 34 43 File pathSeparator 43 34 A
  • 日志工具Log4J

    目前在java编程中 xff0c 日志已经发展出一套成熟的机制 常用的日志控件有Commons logging log4j以及JDK自带的Logging 从最初的System out println 到现在的Log4j xff0c java
  • CAS单点登录(七)——自定义验证码以及自定义错误信息

    在前面我们讲解了CAS单点登录 六 自定义登录界面和表单信息 xff0c 知道了如何去实现页面和表单信息的自定义信息提交 xff0c 就像我们提交表单的信息可能包括手机 邮箱等等 xff0c 这些都能以我们前面的知识点去解决 但平时登录我们
  • Http协议之Request和Response

    协议版本 xff1a Http 1 0 Http 1 1 http1 0协议中 xff0c 客户端与服务器建立连接后 xff0c 只能获得一个 web 资源 http1 1协议中 xff0c 客户端与服务器建立连接后 xff0c 在一个连接
  • Cookie详解

    介绍Cookie xff0c 我们先了解一下什么是会话 会话 xff1a 用户开一个浏览器用于查询相关信息 xff0c 点击多个超链接 xff0c 访问对应的多个web资源 xff08 需要查询的资源 xff09 xff0c 然后关闭浏览器
  • Session浅谈

    在web开发中 xff0c 服务器可以为每个用户浏览器创建一个会话对象 xff08 Session对象 xff09 xff0c 注意 xff0c 一个浏览器独占一个session对象 xff08 默认情况下 xff09 因此 xff0c 在
  • JSP语法(一)

    JSP模板元素 JSP页面中的HTML内容称之为JSP模板元素 JSP模板元素定义了网页的基本骨架 xff0c 即定义了页面的结构和外观 JSP脚本表达式 JSP脚本表达式用于将程序数据输出到客户端的语法 xff1a lt 61 变量或表达
  • ServletConfig对象讲解

    ServletConfig最大的作用就是在一个servlet项目中 xff0c 有些东西不适合在程序中写死 xff0c 这些个东西就可以通过配置的方式添加到servlet的配置文件web xml中 在servlet的配置文件web xml中
  • spring的xml文件不给提示

    解决方法 xff1a 1 window gt preferences gt myeclipse gt Files and Editors gt xml gt xml Files gt Xml Catalog 或者直接到Preferences
  • Navicat 连接 MySQL 1045 错误

    navicat for mysql 连接本地数据库出现1045错误 如下图 xff1a 查了很多资料 xff0c 意思是说mysql没有授权远程连接 xff0c 也就是权限不够 xff1b 解决方法 xff1a 1 首先打开命令行 xff1
  • 网络编程(一)

    本节主要讲网络编程的一些个概念 计算机网络 把分布在不同地理区域的计算机与专门的外部设备用通信线路互相连成一个规模大 功能强的网络系统 xff0c 从而使众多计算机可以方便的互相传递信息 xff0c 共享硬件 xff0c 软件 数据信息等资
  • 网络编程(二)InetAddress和InetSocketAddress

    本节主要讲InetAddress和InetSocketAddress这两个类 InetAddress 封装计算机的IP地址和DNS xff0c 没有端口 1 静态方法获取对象 InetAddress InetAddress getLocal
  • 网络编程(三)URL爬虫原理

    URL和URI的概念 URI xff08 Uniform resource identifier xff09 统一资源标识符 xff0c 用来唯一的标识一个资源 URL xff08 Uniform resource Locator xff0
  • Android lottie java.lang.IllegalStateException: Missing values for keyframe. 问题解决

    对接lottie时 xff0c 根据Lottie用法 xff0c 加载json xff0c 效果显示不出来 xff0c lottie官网上预览json显示正常 xff0c 大量搜索后 xff0c 发现lottie低版本 xff0c 不适用现
  • 网络编程(四)UDP通信

    UDP 以数据为中心 xff0c 非面向连接 xff0c 不安全数据可能丢失但是效率高 xff0c 例如短信 涉及到的类 DatagramSocket 和 DatagramPacket DatagramSocket 此类表示用来发送和接收数
  • 网络编程(五)Socket通信

    在网络编程 xff08 四 xff09 中学习了udp通信 udp通信是非面向连接的 效率高但不安全的通信 而socket通信是基于tcp协议 xff0c 建立稳定连接的点对点的通信 比如打电话 实时 快速 安全性高 占用系统资源高 效率低
  • 网络编程(六)聊天室代码实现

    先写一个客户端输入数据 xff0c 服务器端处理数据后返回给客户端 客户端 xff1a public static void main String args throws UnknownHostException IOException
  • 设计模式——单例模式

    设计模式包括三大类 创建型模式 xff08 主要用来建立对象 xff09 单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式 结构型模式 适配器模式 桥接模式 装饰模式 组合模式 外观模式 享元模式 代理模式 行为型模式 模板方法模式