【设计模式-2.1】创建型——单例模式

说明:设计模式根据用途分为创建型、结构性和行为型。创建型模式主要用于描述如何创建对象,本文介绍创建型中的单例模式。

饿汉式单例

单例模式是比较常见的一种设计模式,旨在确保对象的唯一性,什么时候去使用这个对象都是同一个。这样设计的目的是为了避免对象重复创建,浪费资源,同时也保证了对象的唯一性,不至于多个相同的对象,状态不一致的情况。

以下是单例模式的简单实现:

/**
 * 太阳类
 */
public class Sun {
    
    private static final Sun sun = new Sun();

    private Sun() {
    }

    public static Sun getInstance() {
        return sun;
    }
}

需要注意,对象的创建是在对象类内部,且为static final修饰,并且私有化构造方法,使其不能在外部被创建,其次创建一个静态方法,返回其对象

此时,外部通过类名.方法名的方式,可以访问到该对象,且始终为同一个;

public class Test {
    public static void main(String[] args) {
        Sun sun1 = Sun.getInstance();
        Sun sun2 = Sun.getInstance();
        System.out.println(sun1 == sun2);
    }
}

两次获取到的对象相同

在这里插入图片描述

上面这种创建方式,称为饿汉式单例(Eager Singleton),即类加载完成时就创建对象

懒汉式单例

以下这种方式,称为懒汉式单例(Lazy Singleton),在调用静态方法时才创建对象

/**
 * 懒汉式单例模式
 */
public class LazySun {
    
    private static LazySun sun = null;

    private LazySun() {
    }

    public static LazySun getInstance() {
        if (sun == null) {
            sun = new LazySun();
        }
        return sun;
    }
}

这种创建方式,可以实现延迟加载,节约资源。但是在多线程并发时,如果有多个线程在if (sun == null),就会导致对象被创建多次,所以我们很容易想到的是加锁,将静态方法加上锁,如下:

/**
 * 懒汉式单例模式
 */
public class LazySun {

    private static LazySun sun = null;

    private LazySun() {
    }

    public synchronized static LazySun getInstance() {
        if (sun == null) {
            sun = new LazySun();
        }
        return sun;
    }
}

但是,给方法加上锁后,会影响性能,可以考虑减少锁的范围,只锁住创建对象这一行,如下:

/**
 * 懒汉式单例模式
 */
public class LazySun {

    private static LazySun sun = null;

    private LazySun() {
    }

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

双重检查锁定

但是,还有问题。在多线程并发下,如果线程A在创建对象(未完成),线程B、C在if (sun == null) 这里判断为true,即便对象创建完成,线程B、C通过了if判断,也还是会依次再创建对象,也造成了对象被重复创建。因此,还需要改造,如下:

/**
 * 双重检查锁定
 */
public class LazySun {

    private volatile static LazySun sun = null;

    private LazySun() {
    }

    public static LazySun getInstance() {
        // 第一次判断
        if (sun == null) {
            synchronized (LazySun.class) {
                // 第二次判断
                if (sun == null){
                    sun = new LazySun();
                }
            }
        }
        return sun;
    }
}

就是在锁住的代码块里面再进行一次非空判断,称为双重检查锁定(Double-Check Locking),同时,单例对象修饰符加上volatile,确保多个线程都能正确处理;

IoDH

饿汉式单例,是在类被加载时就创建了对象。不需要考虑多线程,但是无论是否使用到对象都创建,造成了资源浪费。而懒汉式单例,虽然做到了延迟加载,但是需要处理好多线程情况下的对象创建,使用了锁,影响了性能。

那有没有一种更好了方式,既能在多线程下使用,又不会影响性能?

在《设计模式的艺术》(刘伟著)中作者提供了一种更好的创建方式,称为IoDH(Initialization on Demand Holder,按需初始化),代码如下:

/**
 * IoDH
 */
public class Singleton {

    private Singleton() {
    }

    private static class HolderClass {
        private final static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return HolderClass.instance;
    }
}

这种方式是对饿汉式单例的改进,是在单例类里创建了一个内部类,将单例对象的创建放在了这个内部类里面。因为单例对象不是单例类的一个成员变量,所以对象在类加载时不会被创建,而是会在调用静态方法时被创建,这样既能延迟加载,又没有使用锁,影响性能,一举两得。

书中说,通过使用IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能。因此,IoDH不失为一种最好的Java语言单例模式实现方式;其缺点是与编程语言本身的特性相关,很多面向对象语言不支持IoDH。

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于IDEA+SpringBoot+微服务开发的P2P平台项目

基于springboot的社区养老医疗综合服务平台 项目介绍💁🏻 项目名称:基于P2P的金融项目 一个基于P2P(点对点)模式的金融服务平台,致力于提供透明、高效、安全的金融服务。我们的目标是连接借款人与投资者&am…

【LM、LLM】浅尝二叉树在前馈神经网络上的应用

前言 随着大模型的发展,模型参数量暴涨,以Transformer的为组成成分的隐藏神经元数量增长的越来越多。因此,降低前馈层的推理成本逐渐进入视野。前段时间看到本文介绍的相关工作还是MNIST数据集上的实验,现在这个工作推进到BERT上…

linux 账号管理实例一,stdin,passwd复习

需求 账号名称全名次要用户组是否可登录主机密码 myuser1 1st usermygroup1yespasswordmyuser22st usermygroup1yespasswordmyuser33st user无nopassword 第一:用户,和用户组创建,并分配有效用户组(初始用户组是passwd里…

Postman如何使用(二):Postman Collection的创建/使用/导出分享等

一、什么是Postman Collection? Postman Collection是可让您将各个请求分组在一起。 您可以将这些请求组织到文件夹中。中文经常将collection翻译成收藏夹。如果再下文中看到这样的翻译不要觉得意外。Postman Collection会使你的工作效率更上一层楼。Postman Colle…

7、独立按键控制LED状态

按键的抖动 对于机械开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性作用&#xff0c;一个开关在闭合时不回马上稳定地接通&#xff0c;在断开时也不会一下子断开&#xff0c;所以在开关闭合及断开的瞬间会伴随一连串的抖动 #include <REGX52.H…

面试必问:如何快速定位BUG?BUG定位技巧及N板斧!

01 定位问题的重要性 很多测试人员可能会说&#xff0c;我的职责就是找到bug&#xff0c;至于找原因并修复&#xff0c;那是开发的事情&#xff0c;关我什么事&#xff1f; 好&#xff0c;我的回答是&#xff0c;如果您只想做一个测试人员最基本最本分的事情&#xff0c;那么可…

RabbitMQ快速学习之WorkQueues模型、三种交换机、消息转换器(SpringBoot整合)

文章目录 前言一、WorkQueues模型消息发送消息接收能者多劳 二、交换机类型1.Fanout交换机消息发送消息接收 2.Direct交换机消息接收消息发送 3.Topic交换机消息发送消息接收 三、编程式声明队列和交换机fanout示例direct示例基于注解 四、消息转换器总结 前言 WorkQueues模型…

visual stdio动态库的使用

导出类和使用方式 #ifndef PCH_H #define PCH_H// 添加要在此处预编译的标头 #include "framework.h"#ifdef _WIN32 #ifdef MYCLASS_EXPORTS #define MYCLASS_API __declspec(dllexport) #else #define MYCLASS_API __declspec(dllimport) #endif #else #define MYC…

『亚马逊云科技产品测评』活动征文|低成本搭建物联网服务器thingsboard

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道。 0. 环境 - ubuntu22&#xff08;注意4G内存勉强够&#xff0c;部署完…

大一统模型 Universal Instance Perception as Object Discovery and Retrieval 论文阅读笔记

Universal Instance Perception as Object Discovery and Retrieval 论文阅读笔记 一、Abstract二、引言三、相关工作实例感知通过类别名进行检索通过语言表达式的检索通过指代标注的检索 统一的视觉模型Unified Learning ParadigmsUnified Model Architectures 四、方法4.1 Pr…

【蓝桥杯省赛真题48】Scratch放大镜游戏 蓝桥杯scratch图形化编程 中小学生蓝桥杯省赛真题讲解

目录 scratch放大镜游戏 一、题目要求 编程实现 二、案例分析 1、角色分析

我叫:希尔排序【JAVA】

1.我兄弟存在的问题 2.毛遂自荐 希尔排序提希尔(Donald Shell)于1959年提出的一种排序算法。 希尔排序&#xff0c;也称递减增量排序算法&#xff0c;是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。 希尔排序是基于插入排序的以下两点性质而提出改进方法的&…

【教学类-06-10】20231125(55格版)X-Y之间“乘法*题”(以1-9乘法口诀表为例)(随机抽取和正序抽取)

图片展示 &#xff08;随机打乱排序&#xff09; 正序&#xff08;每张都一样&#xff09; 背景需求&#xff1a; 2023年11月24日&#xff0c;准备了一些题目&#xff0c;分别给大4班孩子介绍“5以内加法、5以内减法、5以内加减混合”““10以内加法、10以内减法、10以内加减…

机器学习之自监督学习(四)MoCo系列翻译与总结(一)

Momentum Contrast for Unsupervised Visual Representation Learning Abstract 我们提出了“动量对比”&#xff08;Momentum Contrast&#xff0c;MoCo&#xff09;来进行无监督的视觉表示学习。从对比学习的角度来看&#xff0c;我们将其视为字典查找&#xff0c;通过构建…

移动机器人路径规划(七)--- 基于MDP的路径规划MDP-Based Planning

目录 1 什么是MDP-Based Planning 2 worst-case analysis for nondeterministic model 3 Expected Cost Planning 4 Real Time Dynamic Programming&#xff08;RTDP&#xff09; 1 什么是MDP-Based Planning 之前我们从起点到终点存在很多可执行路径&#xff0c;我们可以…

物联网后端个人第十二周总结

学习工作进度 物联网方面 1.模拟设备通过规则引擎将数据通过mqtt进行转发 在物联网平台上实现模拟设备通过规则引擎将数据通过mqtt进行转发已经全部完成了&#xff0c;所使用的物联网平台在这方面有不少的问题和bug&#xff0c;也可能是没有按照开发者的想法对平台进行使用才导…

基于微信小程序的员工宿舍报修系统

项目介绍 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时…

Leetcode—83.删除排序链表中的重复元素【简单】

2023每日刷题&#xff08;四十&#xff09; Leetcode—83.删除排序链表中的重复元素 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* deleteDuplicates(struct ListNode* head) {i…

张弛声音变现课,枪战电影高能量、快速节奏

在执行枪战片的声音配音任务时&#xff0c;配音员应该致力于传递出戏剧性的紧张氛围与动作场面的激烈感。枪战场景往往是高能量、快速节奏的&#xff0c;这就要求配音不仅要与视觉动作紧密结合&#xff0c;还要通过声音来增强动作的逼真度和观众的紧迫感。以下是针对枪战电影进…