多线程--单例模式and工厂模式

【通过STM32CubeMx配置LWIP+FreeRTOS并通过Socket实现TCP_Client/Sever】 生成KEIL工程之后,勾选上use MicroLIB,代码上暂时无需做其他修改,编译下载。由于使用了FreeRTOS,因此系统的TimeBase Source修改成TIM1。在CubeMx上面选择NUCLEO-F429ZI开发板,并采用默认配置。打开电脑命令行,去ping这设置好的IP,能够实现Ping通。使能LWIP,并且先禁用DHCP,设置好静态IP。修改defaultTask的栈大小。Platform选择LAN8742。修改堆栈大小,生成工程。使能FreeRTOS。 阅读详情

一.什么是设计模式

设计模式好⽐象棋中的"棋谱".红⽅当头炮, ⿊⽅⻢来跳.针对红⽅的⼀些⾛法,⿊⽅应招的时候有⼀ 些固定的套路.按照套路来⾛局势就不会吃亏.

 软件开发中也有很多常⻅的"问题场景".针对这些问题场景,⼤佬们总结出了⼀些固定的套路.按照这 个套路来实现代码,也不会吃亏.

设计模式与框架(spring...)的区别 

框架是一种硬性要求 就是必须服从框架的规范

设计模式是软性要求 灵活度高 根据需求可以调整

二. 什么是单例模式

单例模式是主流23种设计模式的一种具体是哪23种可以AI一下

单例模式是一种典型的模式,也是比较简单的模式,日常开发中更容易用到的模式

单例模式能保证某个类在程序中只存在唯⼀⼀份实例,不能创建多个实例

比如在JDBC中的DateSource就只能创建一个实例

毕竟数据库的数据大小动辄上百的G 多创建一个实例多的存储开销可不是一般的大,更影响性能,数据库的数据就那些创建多个实例也没必要

 单例模式具体的实现⽅式有很多,常见的还是饿汉模式和懒汉模式

饿汉模式:

class SingletonHungry {                                                                                         
    //静态成员的初始化是在加载的阶段触发的 类加载往往就是在程序时候就会触发                                                                       
    private static SingletonHungry instance = new SingletonHungry();//如果带参数 下面构造方法 也要调用带有参数的                    
                                                                                                                
    public static SingletonHungry getInstance() {                                                               
        return instance;//统一后面用这个方法来获取实例                                                                        
                 //由于这里是读取操作不涉及线程安全                                                                             
    }

//.........类的内容                                                                                                           
                                                                                                                
    //私人构造方法                                                                                                    
    private SingletonHungry() {                                                                                 
        //点睛之笔 不让在外部构造实例                                                                                        
    }                                                                                                           
}                                                                                                               
public class Demo26 {                                                                                           
    public static void main(String[] args) {                                                                    
        SingletonHungry t1 = SingletonHungry.getInstance();                                                     
        SingletonHungry t2 = SingletonHungry.getInstance();                                                     
        System.out.println(t1 == t2);                                                                           
                                                                                                                
        //SingletonHungry t3 = new SingletonHungry();报错                                                         
    }                                                                                                           
}                                                                                                               
                                                                                                                

 

饿汉模式顾名思义就是饥饿迫切的在类中构建一个实例(static静态变量,在JVM进行类加载的时候就创建) 由于是单例模式,类中就已经实例出来类的对象以后就通过类名来调用它的实例,构造方法修改为private不让外部再创建实例,由于获取实例是读取操作是原子的所以是天然的线程安全的

懒汉模式:

懒汉模式在类加载的时候不创建实例,在第一次使用的时候创建,如果一直不适用也就没必要创建了,省去了一些内存性能的开销

假设一个小说(千万字)肯定是只把一部分展示出来,后续如果用户翻页,随着翻页,随时就在后续数据,如果全部加载出来,可能会导致程序崩溃

打开编译器的把所有内容,都是从文件加载到内存中,再显示

class SingletonLazy {
    private static SingletonLazy instance = null;

    //1
    public static SingletonLazy getInstance() {
        //这样有线程安全问题
        //在多个线程下由于这个操作不是原子的 会由于线程的随机调度引发创建实例覆盖的问题
        if (instance == null) {//防止new多个实例
            instance = new SingletonLazy();//创造时机是在第一次使用的时候 而不是在程序启动的时候(节省空间资源更推荐)
        }
        return instance;
    }
}

上述懒汉方式由于if(判断)读操作 和new实例(修改操作)涉及一个读操作一个写操作不是原子的在单线程中不涉及线程安全,在多线程中线程安全问题就很明显,如下↓

第一个线程new出来对象,由操作系统的调度器,调度到线程二开始执行new操作,随着第二个线程的覆盖操作,第一个new出来的对象随后会被JVM的垃圾回收 回收掉 

两次new操作在数据很少的时候其实都无所谓,但是还是拿JDBC中new DataSource的时候数据内存很大可能new一个就要十分钟 如果出现两次new操作就会大大削减性能,甚至还会导致服务器崩溃

所以要解决

解决不是原子性问题肯定是要加锁

加上synchronized可以改善这⾥的线程安全问题.

class SingletonLazy {
    private static SingletonLazy instance = null;

    private static Object locker = new Object();//锁对象

    public static SingletonLazy getInstance() {
        //为了解决原子性问题就要加锁
        /**
         * 引入锁之后 后执行的线程在加锁的位置阻塞 阻塞到前一个线程解锁
         * 当后一个线程进入条件的时候 前一个线程已经修改完毕
         * isnstance不会再为null 就不会后续的new
         * 两个线程两把锁(这里只有一把锁) 无法构成请求和保持 不会死锁
         */
        synchronized (locker) {//也可以再函数首部加锁
            if (instance == null) {
                instance = new SingletonLazy();
            }
        }

        /**
         * 实例创建好后 后去再调用该方法 都是直接return 如果只是进行if(判定) + 读取return 就不涉及到线程安全的问题了
         * 但是每次调用上述方法 都会触发依次加锁的操作 虽然不涉及安全问题了
         * 多线程的情况下 这里的加锁 就会相互阻塞 影响程序的执行效率  
         */
        return instance;
    }

引入锁之后,后执行的线程就会在加锁的位置阻塞,一直阻塞到前一个线程解锁

当后一个线程进入条件的时候,前一个线程已经修改完毕 instance不再为null就不会进行后续的new操作

但是加入锁之后就引入了一个新的问题:

实例创建好后 后去再调用该方法 都是直接return

如果只是进行if(判定) + 读取return(纯读取的操作) 就不涉及到线程安全的问题了 但是每次调用上述方法 都会触发依次加锁的操作

虽然不涉及安全问题了 多线程的情况下 这里的加锁 就会相互阻塞 影响程序的执行效率 所以要改善效率问题

 getInstance可以这样改

public static SingletonLazy getInstance() {
        if (instance == null) {//判断是否需要加锁
            synchronized (locker) {
                if (instance == null) {//判断是否需要new对象 两个if在单线程中执行流只有一个 if判定结果一样
                                        //在多线程中其他线程可能就会把if中的instance变量给修改了也倒是两次的if结果的结论不同
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }

 在锁的外面再加一层if条件的判断来判断是否需要加锁,两个if执行的意义不一样可看代码注释

还有一些其他问题:

内存可见性,就不如再t1线程在读取instance的时候,t2线程进行修改,由于编译器的内存优化的逻辑非常复杂保险起见还是在instance上加一个volatile关键字,从根本上杜绝内存可见性问题

还有一个更关键的问题:指令重排序

指令重排序也是编译器优化的一种体现形式,编译器会在逻辑不变的前提下,调整你的代码顺序表来达到提升性能的效果

编译器优化往往不只是javacode自己的工作,通常是javac和JVM配和的效果(甚至是操作系统也要参与配合)

上述这个代码的机器指令中

instance = new SingletonLazy();
三步骤:1.申请内存空间 2.在空间上构造对象(初始化) 3.内存空间的首地址赋值给引用变量
* 正常来说按照123的顺序执行命令
* 但是在指令重排序的情况下会成为132这样的顺序 单线程123 132都一样 多线程可能有bug
* 可能会拿着未初始化的实例来进行操作

 如下图指令重排序的bug

 

解决的话还是在instance 上加上volatile关键字预防指令重排序问题 

    private static volatile SingletonLazy instance = null;
volatile的功能两方面
* 1.确保每次读取操作都是读内存
* 2.关于变量的读取和修改操作不会引起指令的重排序(主要)

三.工厂模式

我们先来看一个场景

在一个平面直角坐标系中描述一个点的位置,可以通过x,y两点的坐标直接确立,也可以通过极坐标的半径r和α角来确立.

class Point {
    public Point(double x, double y) {
        //构造点的坐标
    }

    public Point(double r, double a) {
        //构造点的极坐标
    }
  
}
上述两个构造方法是在平面直角坐标系中确定一个点
第一个方法是直角坐标系 第二个方法是极坐标系
两个方法构成冲突也不能重载(overload)

解决方法就是利用工厂方法

利用一个工厂类来提供工厂方法

class Point {

}

class PointFactory {
    //工厂方法
    public static Point makePointByXY(double x, double y) {
        Point p = new Point();
        //通过x 和 y给p进行属性设置
        return p;//返回构造好的Point对象
    }

    public static Point makePointByRA(double r, double a) {
        Point p = new Point();
        //通过r 和 a给p进行属性设置
        return p;
    }
}

工厂方法的核心,通过静态方法,把构造对象new的过程各种属性初始化的过程给封装起来
提供多组静态方法 实现不同情况的构造

 

使用就可以这样使用 通过拿Point类来接受工厂方法的返回值也就类似于Point 来new实例了

public class Demo {
    public static void main(String[] args) {
        Point p = PointFactory.makePointByXY(10, 20);
    }
}

上述只是一个工厂模式使用的案例:解决构造方法冲突 还有其他的作用,如下:

1.解耦对象的创建和使用

2.提高代码的可维护性和可扩展性

3.便于代码的重复使用

4.便于对象的管理和控制

 当然也有缺点:复杂性增加,还需要权衡选择不要过度依赖,造成代码冗余

 

基于STM32L4XX、HAL库的 L76KB-A58定位模块驱动程序设计 / 确保字符串终止。// 缓冲区溢出,重置。// 重置缓冲区索引。支持GPS、GLONASS、Galileo、北斗和QZSS多系统定位。case 1: // UTC时间。// 配置GPS模块(可选)// 查找GGA语句。// 启动UART接收。// USART1初始化函数。内置LNA和SAW滤波器。 阅读详情

相关推荐

高通引导文件获取全攻略:ELF/MBN提取与EDL救砖实战

在智能手机底层维护中,引导加载程序(Bootloader)是系统启动的第一道关卡。高通平台通过PBL、SBL1/XBL等阶段完成硬件初始化和安全校验,一旦引导分区损坏,设备便可能陷入黑砖状态。此时,掌握ELF与MBN格式的引导镜像获取方法,成为维修工程师和刷机用户的核心技能。通过官方固件包解包或借助EDL模式直接从设备分区备份,均能获得原厂匹配的引导文件。配合Firehose工具和9008端口通信,即可实现分区级读写与救砖恢复。本文从启动链路原理出发,对比两种获取路径的适用场景,并针对驱动识别、文件校验、分

weixin_30175731的博客 421

【Java EE】-多线程编程(八) 多线程案例之线程池&&工厂模式

什么是线程池,线程池的应用,用普通方法替代构造方法实现工厂模式。线程池标准库的使用,变量捕获,关于线程池的源码分析,ThreadPoolExecutor的构造方法参数分析,线程池拒绝策略。自定义实现线程池。

m0_63979882的博客 733

STM32实战指南:TFTLCD液晶屏驱动与ILI9341应用解析

本文详细解析了STM32驱动TFTLCD液晶屏的实战技巧,重点介绍了ILI9341控制器的硬件连接、寄存器操作及性能优化方法。通过8080并行接口时序分析、GRAM操作优化和DMA传输应用,帮助开发者高效实现液晶屏驱动,适用于工业控制、智能家居等场景。

weixin_26873711的博客 232

java多线程之流水线工厂模式

在主函数里我们创建一个队列来储存任务,并将任务传到每一个线程里来完成加工操作,然后调用start方法开起线程,再调用join方法等待所有线程都完成之后将每个成品打印出来。当第一个产品到第一个工作间用时1个单位时间,再接着进入第二个工作间依次下去,就当第一个产品完成第一个工作间任务时,第二个进入一个工作间。当我们需要对一个产品进行多次不同的操作时,比如我们要对一个队列List 进行加工,先将List传入T1工作间,加工完后,再传入T2、T3进行加工,最后得到成品。这时我们就用到流水线工厂模式进行加工。

woai3364的博客 726

手把手教你:基于STM32H7自制飞控,如何从零开始移植PX4固件(附避坑指南)

本文详细介绍了如何基于STM32H7自制飞控板并移植PX4固件的完整流程,包括硬件设计、开发环境搭建、关键配置文件移植、驱动开发与适配等关键步骤。特别针对PX4-AutoPilot的移植过程提供了实用技巧和避坑指南,帮助开发者高效完成飞控系统开发。

weixin_30271335的博客 143

【AI编程】用AI开发STM32软件(1):环境配置+AI编写LED闪烁

现在AI编程这么火,不拿来开发嵌软也太可惜了。笔者最近刚好有个2学分的实践课,要自己做项目,这不,机会就来了。笔者特意记录下来其过程,以供大家学习和参考。使用:VSCode+Copilot+EIDE+STM32CubeMX,单片机用最经典的stm32f103c8t6+STLink。

qq_23220445的博客 4572

【多线程】(五)工厂模式和线程池

线程池是一种管理和复用线程的机制。线程池维护着一个线程队列,其中包含着多个准备好的线程。当有任务需要执行时,线程池中的线程可以被分配来执行任务,执行完成后又可以返回线程池以供下一次使用。

qq_61635026的博客 1115

51单片机入门指南-基于STC89C52(持续更新)

一、环境介绍 编程IDE: keil5 单片机型号: STC89C51/52 开发板: 普中科技的开发板 完整PDF资源下载地址:https://download.youkuaiyun.com/download/xiaolong1126626497/19785856 二、51单片机开发手册介绍 2.1 前言 51单片机是对所有兼容Intel 8031指令系统的单片机的统称。 该系列单片机的始祖是Intel的8004单片机,后来随着Flash rom技术的发展,8004单片机取得了长足的进展,成为应用最.

8797

【多线程】线程工厂模式创建多线程

通过实现ThreadFactory 来创建线程工厂public class TestingThreadFactory implements ThreadFactory{ //Executors 线程池的顶级接口,创建默认线程工厂 ThreadFactory factory=Executors.defaultThreadFactory(); @Override ...

sinat_35821285的博客 1150

CDD数据库文件制作(二)——服务配置(0x27)

主要根据诊断调查表,针对0x27服务在CDD中的每一步配置给出详细介绍 1.会话切换配置 1.1.根据诊断调查表进行信息提取 1.2.子功能添加 1.2.1.Level1安全等级1创建 1.2.2.Level3安全等级3创建 1.2.3.安全等级名字查看与修改 1.3.会话切换信息提取(应用程序下) 1.4.会话转换配置(应用程序下) 1.5.会话切换信息提取(引导程序下) 1.6.会话转换配置(引导程序下) 2.安全等级配置信息提取 2.1.安全访问配置(level1) 2.2.安全访问配置(level2

LOVE135149的博客 2929

别再只当调包侠了!YOLO检测头到损失函数全链路拆解,看完才算真懂

YOLO的精妙不在于某个单一创新,而在于各模块围绕“实时精准检测”这一目标的协同设计。Backbone追求高效特征压缩,Neck保障多尺度信息流通,Head解耦任务冲突,Loss动态引导优化方向。只有理解这套内在逻辑,才能跳出“调包-试错”的低效循环,在面对新场景、新问题时做出有理有据的改进决策。技术深度决定职业天花板。下次再调YOLO时,不妨先问自己:我改的这个参数,到底影响了系统中的哪一环?参考资料。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 186

设计模式:单例模式和工厂模式

单例模式与工厂模式的基本原理和实现,以及单例模式结合工厂模式的基本应用。

Sinder小德的博客 6786

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

单例模式和工厂模式

设计模式 1.单例模式 定义: 单例模式要求某一类能够有返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称)。 使用场景: 1.需要频繁的进行创建和销毁的对象; 2.创建对象时耗时过多或耗费资源过多,但又经常用到的对象; 3.工具类对象; 4.频繁访问数据库或文件的对象。 创建方式: // 饿汉式: public class...

qq_43670845的博客 9549

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

单例模式与工厂模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,其目的是确保一个类仅有一个实例,并提供一个全局访问点来获取该实例。单例模式广泛应用于需要控制资源访问的场合,比如配置文件读取、数据库连接、线程池等。

2302_78814792的博客 2330

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C++单例模式、工厂模式

线程安全的懒汉式单例和饿汉式单例,三种最基本的工厂模式:简单工厂,工厂方法模式,抽象工厂,以及封装性更为良好的模板工厂,“产品注册制工厂”(产品注册模板类 + 单例工厂模板类)。

m0_75034791的博客 1945

7、【C++】单例模式/工厂模式

单例模式、工厂模式

阿牧路泽 2141

简介单例模式(静态工厂模式)和工厂模式

单例模式就是保证系统中这个对象只有一个实例 什么是单例模式?       单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。   1、一个单例模式的要求有三点: 1)私有的变量 2)私有的构造函数 3)公有的方法,返回一个实例对象 2、实现单例的方式(举例) 1)饿汉模式:饿汉式单例在类加载初始化时就创建好一个静态的对象供外部使用,除非系统重启,这...

qq_43154385的博客 5350

设计模式-单例模式&工厂模式

1. 在内存中只有一个对象,节省内存空间2. 避免频繁的创建销毁对象,可以提高性能。工厂类包含必要的逻辑判断,可以根据用户需求动态实例化相关的类。客户端可以免除直接创建产品对象的职责,去除了与具体产品的依赖。工厂和产品的职责区分明确。工厂方法模式 = 简单工厂模式 + 开闭原则1、抽象工厂模式隔离了具体产品的生产,使得客户并不需要知道什么产品被创建,一个工厂可以创建各种产品。2、当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

m0_74380601的博客 2583

单例模式-工厂模式

一:单例模式 1.单例模式只能有一个实例 2.单例必须自己创建自己的唯一实例 3.单例必须给所以其他对象提供这一实例 在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例,这些应用或多或少具有资源管理器的功能。 单例模式之懒汉单例: //0.创建自己的单例程序 class MySingle2{ //6.2创建一个静态的唯一的锁对象 static Object o = new Object(); //1.私有化本类的构造方法 p

Mr_Jin的博客 4408

C++单例模式与工厂模式

工厂模式中对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。在这懒汉式用的是静态局部变量的方法,充分使用了静态局部变量的特点。C#当中弱化了全局变量的声明与定义的概念,用C#写单例也相对简单的多。抽象产品类、具体产品类、抽象工厂类、具体工厂类。抽象产品类、具体产品类、抽象工厂类、具体工厂类。抽象产品类、具体产品类、一个简单工厂类。一个具体的工厂可以生产多个具体产品。每个具体工厂只能生产一种具体的产品。...

qq_42987967的博客 1524

工厂模式和单例模式

什么是工厂模式? 通过一个工厂类创建类似功能的不同实现类的父类或接口,不用关注你所获取的类是怎么实现的,只要通过工厂获取到对 象即可使用 工厂模式需要的三大模块: 一个父类或者一个接口:定义该功能的方法、属性 一个实现类或者子类:实现或者继承上面的接口或者父类 工厂类:通过工厂类获取实现类的父类或者接口(多态) 优点: 扩展性高:当你想增加一个产品,只需要扩...

wong_shenshen的博客 2306

单例模式与多线程

在单例模式与多线程技术相结合的过程中,我们能发现许多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。线程与某些技术相结合时,我们需要考虑的事情会更多。总的来说,在本节我们只需要考虑一件事,那就是:如何使单例模式与多线程结合时是安全的、正确的。

m0_62943934的博客 1976

详解单例模式和工厂模式(面试)

1. 什么是设计模式 设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路,他不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳定性以及安全性的解决方案。 1995年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了23种设计模式,从此树立了软件设计模式领域的里程碑,人称[GoF设计模式]。 2. 学习设计模式的意义 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继

qq_35254085的博客 1872

常见的设计模式【单例模式&工厂模式】

常见开发模式中单例模式、工厂模式的相关介绍

yifei_345678的博客 1047

【多线程】单例模式

本期内容主要介绍单例模式的含义,以及两种实现单例模式的方式,饿汉模式和懒汉模式,其中懒汉模式线程不安全,可以通过加锁将if操作和new操作变成原子操作,通过双重if提高效率,使用volatile关键字禁止指令重排序。

爱编程爱运动的博客 5030

设计模式一(工厂模式、抽象工厂模式、单例模式)

本文从总结的角度去学习23种设计模式去掉不应有的废话。适合复习阅读和部分初学者。

wangxiaai的博客 4048
上一篇: 多线程--阻塞队列and生产消费者模型
下一篇: 多线程--线程池
刘 大 望
博客等级 码龄2年 896粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值