23种设计模式之创建型模式 - 单例模式

news2024/11/27 18:35:45

文章目录

  • 一、单例模式
    • 1.1单例模式定义
    • 1.2 单例模式的特点
  • 二、实现单例模式的方式
    • 2.1 饿汉式
    • 2.2 懒汉式
    • 2.3 双重检查锁:
    • 2.4 静态内部类
    • 2.5 枚举实现(防止反射攻击):

一、单例模式

1.1单例模式定义

单例模式确保系统中某个类只有一个实例,并提供一个访问它的全局访问点。主要解决一个全局使用的类频繁地创建与销毁,控制实例数目,节省系统资源。

1.2 单例模式的特点

  • 单例类只能有一个实例
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例
  • 单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性

单例的四大原则:

  • 构造私有
  • 以静态方法或者枚举返回实例
  • 确保实例只有一个,尤其是多线程环境
  • 确保反序列换时不会重新构建对象

二、实现单例模式的方式

2.1 饿汉式

饿汉式单例在类加载初始化时就创建好一个静态的对象供外部使用,除非系统重启,这个对象不会改变,所以本身就是线程安全的。
Singleton 通过将构造方法限定为 private 避免了类在外部被实例化,在同一个虚拟机范围内,Singleton 的唯一实例只能通过 getInstance()方法访问。(事实上,通过 Java 反射机制是能够实例化构造方法为 private 的类的,会使 Java单例实现失效)

/**
 * @Author huang.bX
 * @Date 2021/7/21
 */
public class SingletonTest01 {
    public static void main(String[] args) {
        Hungry instance = Hungry.getInstance();
        Hungry instance1 = Hungry.getInstance();
        Hungry instance2 = Hungry.getInstance();
        System.out.println(instance.getClass());
        System.out.println(instance1.getClass());
        System.out.println(instance2.getClass());
    }
}

//饿汉式
class Hungry {
    //1构造器私有化,外部不能直接new
    private Hungry() {
    }
    //2本类的内部创建实例
    private final static Hungry hungry = new Hungry();

    //提供一个全局访问点共有的静态方法 返回实例对象
    public static Hungry getInstance(){
        return hungry;
    }
}

在这里插入图片描述

2.2 懒汉式

该示例虽然用延迟加载方式实现了懒汉式单例,但在多线程环境下会产生多个 Singleton 对象;

/**
 * @Author huang.bX
 * @Date 2021/7/21
 */
public class SingletonTest03 implements Runnable {

    @Override
    public void run(){
        for (int i=1;i<1000;i++){
            LazyMan lazyMan=LazyMan.getInstance();
            System.out.println(lazyMan.hashCode());
        }
    }
    public static void main(String[] args) {
        /*
         *   LazyMan instance1 = LazyMan.getInstance();
         *   LazyMan instance2 = LazyMan.getInstance();
         *  System.out.println(instance1.hashCode()==instance2.hashCode());
        */
       new Thread(new SingletonTest03()).start();
       new Thread(new SingletonTest03()).start();
       new Thread(new SingletonTest03()).start();


    }
}

class LazyMan{
    private LazyMan(){

    }
    private static LazyMan lazyMan;

    //public static LazyMan getInstance()线程不安全
    public static synchronized LazyMan getInstance(){
        if (lazyMan==null){
           lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

在这里插入图片描述

2.3 双重检查锁:

使用双重检查锁进一步做了优化,可以避免整个方法被锁,只对需要锁的代码部分加锁,可以提高执行效率。

/**
 * @Author huang.bX
 * @Date 2021/7/21
 */
public class SingletonTest05 {
    public static void main(String[] args) {
        DoubleLock instance1 = DoubleLock.getInstance();
        DoubleLock instance2 = DoubleLock.getInstance();
        System.out.println(instance1.hashCode()==instance2.hashCode());
    }
}

class DoubleLock{

    private static volatile DoubleLock doubleLock;
    private DoubleLock(){}

    public static DoubleLock getInstance(){
        if (doubleLock==null){
            synchronized (DoubleLock.class){
                if (doubleLock==null){
                    doubleLock = new DoubleLock();
                }
            }
        }
        return doubleLock;
    }
}

在这里插入图片描述

2.4 静态内部类

这种方式引入了一个内部静态类(static class),静态内部类只有在调用时才会加载,它保证了 Singleton 实例的延迟初始化,又保证了实例的唯一性。它把 singleton 的实例化操作放到一个静态内部类中,在第一次调用 getInstance() 方法时,JVM 才会去加载 InnerObject 类,同时初始hsingleton 实例,所以能让 getInstance() 方法线程安全。特点是:即能延迟加载,也能保证线程安全。静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。

/**
 * @Author huang.bX
 * @Date 2021/7/21
 */
public class SingletonTest06 {
    public static void main(String[] args) {
        StaticInClass instance1 = StaticInClass.getInstance();
        StaticInClass instance2= StaticInClass.getInstance();
        System.out.println(instance1.hashCode()==instance2.hashCode());
    }
}

class StaticInClass{

    private static volatile StaticInClass staticInClass;
    //构造器私有化
    private StaticInClass(){}

    //定义一个静态内部类,该类中有一个静态属性
    private static class Inner{
        private static final StaticInClass INSTANCE = new StaticInClass();
        
    }
    public static synchronized StaticInClass getInstance(){
        return Inner.INSTANCE;
    }

}

在这里插入图片描述

2.5 枚举实现(防止反射攻击):

事实上,通过 Java 反射机制是能够实例化构造方法为 private 的类的。这也就是我们现在需要引入的枚举单例模式。

/**
 * @Author huang.bX
 * @Date 2021/7/21
 */
public class SingletonTest07 {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance1.hashCode());
        System.out.println(instance2.hashCode());
        System.out.println(instance2.hashCode()==instance1.hashCode());
        System.out.println(instance1.getClass());
        System.out.println(instance2.getClass());
        System.out.println(instance1.getDeclaringClass());
    }
}

enum Singleton{
    INSTANCE;//属性
    public void say(){
        System.out.println("ok!");
    }
}

在这里插入图片描述

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

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

相关文章

基于SSM汽车交易系统

基于SSM汽车交易系统的设计与实现 摘要 电子商务的兴起不仅仅是带来了更多的就业行业。同样也给我们的生活带来了丰富多彩的变化。多姿多彩的世界带来了美好的生活&#xff0c;行业的发展也是形形色色的离不开技术的发展。作为时代进步的发展方面&#xff0c;信息技术至始至终…

Geoserver中CQL_FILTER的使用

概述 在Geoserver中可通过CQL_FILTER对要素进行过滤&#xff0c;CQL_FILTER即支持属性过滤也支持空间过滤&#xff0c;本文通过实际的例子演示如何使用CQL_FILTER。 简介 CQL(Common Query Language)是为OGC目录规范创建的纯文本语言。GeoServer对其进行了调整&#xff0c;使…

批量爬取招聘网站【Boss直聘】上工作岗位的招聘信息

不管是学生还是工作的小伙伴&#xff0c;估计都对不同岗位工作几年的薪酬水平比较感兴趣。本文提供爬取招聘网站&#xff0c;获取某类工作招聘信息的实现逻辑和代码。具体的实施步骤是&#xff1a;明确爬取的招聘网站—确定爬取的工作城市—确定爬取的岗位—获取岗位的招聘子链…

前端学习<二>CSS基础——13-CSS3属性:Flex布局图文详解

前言 CSS3中的 flex 属性&#xff0c;在布局方面做了非常大的改进&#xff0c;使得我们对多个元素之间的布局排列变得十分灵活&#xff0c;适应性非常强。其强大的伸缩性和自适应性&#xff0c;在网页开中可以发挥极大的作用。 flex 初体验 我们先来看看下面这个最简单的布局…

【蓝桥杯嵌入式】六、真题演练(一)-1演练篇:第 届真题

温馨提示&#xff1a; 真题演练分为模拟篇和研究篇。本专栏的主要作用是记录我的备赛过程&#xff0c;我打算先自己做一遍&#xff0c;把遇到的问题和不同之处记录到演练篇&#xff0c;然后再返回来仔细研究一下&#xff0c;找到最佳的解题方法记录到研究篇。 解题记录&#x…

了解 LoadRunner 性能测试软件及其基础使用

目录 一、了解LoadRunner 1、什么是Loadrunner&#xff1f; 2、Loadrunner包括什么组件&#xff1f; &#xff08;1&#xff09;前台组件 &#xff08;2&#xff09;后台组件 二、LoadRunner三大组件 1、VuGen&#xff08;虚拟用户脚本生成器&#xff09; &#xff08;…

2024全开源小狐狸ai付费创作系统V2.8.0

源码介绍 小狐狸GPT付费体验系统的开发基于国外很火的ChatGPT&#xff0c;这是一种基于人工智能技术的问答系统&#xff0c;可以实现智能回答用户提出的问题。相比传统的问答系统&#xff0c;ChatGPT可以更加准确地理解用户的意图&#xff0c;提供更加精准的答案。同时&#x…

算法---动态规划练习-10(删除并获得点数)

题目 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 rob_s函数&#xff1a;这个函数实现了经典的"打家劫舍"问题的算法。使用动态规划的思想&#xff0c;通过填表的方式计算在给定范围内能够获取的最大点数。 f和…

Windows入侵排查

目录 0x00 前言 0x01 入侵排查思路 1.1 检查系统账号安全 1.2 检查异常端口、进程 1.3 检查启动项、计划任务、服务 0x00 前言 当企业发生黑客入侵、系统崩溃或其它影响业务正常运行的安全事件时&#xff0c;急需第一时间进行处理&#xff0c;使企业的网络信息系统在最短时…

PAT(多路复用)配置

PAT&#xff08;多路复用&#xff09; 核心&#xff1a;多个内网IP对应一个公共IP 如下图&#xff1a; 配置命令&#xff1a; 第一步&#xff08;定义访问控制列表&#xff09; access-list 编号 permit 网络地址 反掩码 第二步&#xff08;定义合法的外部IP&#xff09; ip …

杰发科技——Jlink插件使用

0. 简介 杰发自带的烧录工具是ATCLink&#xff0c;基于DapLink适配。个人不太喜欢ATCLink&#xff0c;推荐使用Jlink&#xff0c;毕竟自己买&#xff0c;不用问原厂要&#xff0c;而且带Jlink&#xff0c;至少5Mhz以上。 V9烧录器使用7.50以下版本驱动。 V11烧录器可以使用7…

JavaSE:继承和多态(下篇)

目录 一、前言 二、多态 &#xff08;一&#xff09;多态的概念 &#xff08;二&#xff09;多态实现条件 &#xff08;三&#xff09;多态的优缺点 三、重写 &#xff08;一&#xff09;重写的概念 &#xff08;二&#xff09;重写的规则 &#xff08;三&#xff09;重…

AtCoder+ABC129_Typical Stairs

题目描述 有一个有 N 级台阶的楼梯。高桥现在站在楼梯的脚下&#xff0c;也就是第0个台阶上。他可以一次爬上一个或两个台阶。 但是&#xff0c;编号为a[1] ~ a[m]台阶的踏板都坏了&#xff0c;所以踏上这些台阶很危险。 在不踏上坏掉的台阶的情况下&#xff0c;有多少中方案…

《书生·浦语大模型全链路开源开放体系》学习笔记

书生浦语大模型全链路开源开放体系-学习笔记 大模型成为发展通用人工智能的重要途径专用模型通用大模型 书生大模型开源历程InternLM2回归语言建模的本质主要亮点性能全方位提升强大的内生计算能力 从模型到应用典型流程全链条开源开放体系数据数据集获取预训练微调XTuner 评测…

unipush 2.0流程及踩坑记录(后端调用接口,前端推送)

unipush 在线离线示例 在DCLOUD开发者中心里面创建unipush的应用 如果遇到选择Android 包名后没有自动生成Android 应用签名的话&#xff0c;就是下图这样的。 这个情况多半就是通过直接创建云端证书造成的&#xff0c;没有编辑应用信息 没有云端证书的看这里 在我的应用&…

62岁「御用变态佬」近况曝光。

现年62岁的吴毅将于90年代活跃于香港影坛&#xff0c;因经常扮演黑社会大佬、变态色魔等角色&#xff0c;而被封为影坛御用恶人&#xff0c;其反派形象亦深入民心。北上发展多年的吴毅将&#xff0c;近年不时在内地登台&#xff0c;不过日前却有一段他在台上发恶闹观众的片段被…

作业 二维数组-定位问题

图形相似度 描述 给出两幅相同大小的黑白图像&#xff08;用0-1矩阵&#xff09;表示&#xff0c;求它们的相似度。 说明&#xff1a;若两幅图像在相同位置上的像素点颜色相同&#xff0c;则称它们在该位置具有相同的像素点。 两幅图像的相似度定义为相同像素点数占总像素点数…

Linux下开发调试C++代码的三种方法

目录 准备程序配置vscode的json文件调试使用GDB命令行调试使用core文件调试 一般来说&#xff0c;Linux下做C开发都是用vscode远程连接的方式&#xff0c;这时候调试有三种方式&#xff1a;配置vscode的json文件调试、GDB命令行调试、通过core文件调试。 关于这三种调试方法的…

ssm停车场管理系统

点赞收藏关注 → 私信领取本源代码、数据库 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于停车场管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了停…

【PHP编程使用UI框架】——GET和POST的请求方法

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…