设计模式——单例模式八种方式实现与分析(附代码示例)

article/2025/9/19 2:28:10

一. 概念

        所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

        单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new

        单例模式使用的场景: 需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象)但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂 等)

二. 单例设计模式八种方式

1)饿汉式(静态常量) 2)饿汉式 (静态代码块)

3)懒汉式(线程不安全) 4)懒汉式(线程安全, 同步方法) 5)懒汉式(线程安全, 同步代码块)

6)双重检查(推荐)

7)静态内部类(推荐)

8)枚举(推荐)

三. 饿汉式

1. 饿汉式(静态常量)

步骤:

        1. 构造器私有化(防止外部类直接new)

        2. 本类内部创建对象实例

        3. 向外暴露一个静态的公共方法 (getInstance),返回实例对象

代码示例

public class Singleton01 {public static void main(String[] args) {Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance==instance1);}
}class Singleton{//构造器私有化private Singleton(){}//本类内部创建对象实例private final static Singleton singleton = new Singleton();//对外暴露一个静态的公共方法,返回实例对象public static Singleton getInstance(){return singleton;}
}

         instance与instance1相等(hashCode相同),此处也验证了单例模式中,外部访问的实例对象都指向同一个 

2. 饿汉式 (静态代码块)

        在静态代码块中创建单例对象,其他步骤与饿汉式(静态常量)形态

代码示例

//饿汉式 (静态代码块)
class Singleton{private Singleton(){}private static Singleton singleton;//在静态代码块中创建单例对象static {singleton = new Singleton();}public static Singleton getInstance(){return singleton;}
}

3. 饿汉式优缺点分析 

优点:

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

缺点:

        在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

        这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance就没有达到lazy loading的效果

4. 结论

        饿汉式可用,但是可能造成内存浪费,不推荐

四. 懒汉式

        提供一个静态的共有方法,当使用该方法时,才去创建singleton,即为懒汉式

1. 懒汉式(线程不安全)

代码示例

class Singleton{private Singleton(){}private static Singleton singleton;//提供一个静态的共有方法,当使用该方法时,才去创建singleton,即为懒汉式public static Singleton getInstance(){if(singleton == null){singleton = new Singleton();}return singleton;}
}

优缺点分析:

        起到了Lazy Loading的效果,但是只能在单线程下使用。

        如果在多线程下,一个线程进入了if (singleton = nul)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以,在多线程环境下不可使用这种方式。

结论:  在实际开发中,不要使用这种方式。

2. 懒汉式(线程安全, 同步方法)

        通过synchronized关键字加锁实现线程安全

代码示例

class Singleton{private Singleton(){}private static Singleton singleton;//提供一个静态的共有方法,当使用该方法时,才去创建singletonpublic static synchronized Singleton getInstance(){if(singleton == null){singleton = new Singleton();}return singleton;}
}

优缺点分析:

         解决了线程不安全问题

        效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例, 直接return就行了。方法进行同步效率太低

结论: 在实际开发中,不推荐使用这种方式

3. 懒汉式(线程安全, 同步代码块)

代码示例

class Singleton{private Singleton(){}private static Singleton singleton;public static Singleton getInstance(){if(singleton == null){synchronized (Singleton.class){singleton = new Singleton();}}return singleton;}
}

 优缺点分析:

        这种方式,本意是想对懒汉式(线程安全, 同步方法)的改进,因为前面同步方法效率太低,
改为同步产生实例化的的代码块,但是这种同步并不能起到线程同步的作用。跟懒汉式(线程不安全)实现方式遇到的情形一致,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例

结论: 在实际开发中,不能使用这种方式

五. 双重检查

1. 代码示例

class Singleton{private Singleton(){}private static volatile Singleton singleton;public static Singleton getInstance(){if(singleton == null){synchronized (Singleton.class){if(singleton == null){singleton = new Singleton();}}}return singleton;}
}

2.  双重检查优缺点分析

        Double-Check概念是多线程开发中常使用到的,如代码所示,进行了两次if (singleton == nul)检查,就可以保证线程安全。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象,也避免的反复进行方法同步。同时使用volatile关键字,确保了可见性。

        线程安全;延迟加载;效率较高

3. 结论

        在实际开发中,推荐使用这种单例设计模式

六. 静态内部类

1. 代码示例

class Singleton{private Singleton(){}private static class SingletonInstance{private static final Singleton SINGLETON = new Singleton();}public  static Singleton getInstance(){return SingletonInstance.SINGLETON;}
}

2.  静态内部类优缺点分析

        这种方式采用了类装载的机制来保证初始化实例时只有一个线程。静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法, 才会装载SingletonInstance类,从而完成Singleton的实例化。

        类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

        避免了线程不安全,利用静态内部类特点实现延迟加载,效率高

3. 结论

        在实际开发中,推荐使用这种单例设计模式

七. 枚举

1. 代码示例

enum Singleton{SINGLETON;
}

2.  枚举优缺点分析

        借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

        枚举仍然算饿汉式。但是如果一个单例类除了这个单例之外,没有其他静态变量或静态方法,那么直接用饿汉式是很合适的,因为这种情况下除了获取单例之外通常没有其他会导致这个类被加载的情况存在,类加载本身就已经是一种懒加载了。

3. 结论

        在实际开发中,推荐使用这种单例设计模式


http://chatgpt.dhexx.cn/article/yACmv37c.shtml

相关文章

C++ 单例模式 代码详解

单例模式 单例模式(Singleton Pattern)是 最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被…

[设计模式] -- 单例模式

Emai : hahayacodergmail.com 背景 最近在公司的项目中,经常会用到单例模式,由于之前没有想过怎么正确使用单例模式,导致写成的程序中有BUG。在学习Cocos2d-x时,导演类CCDirector等都是单例类。所以从头开始学习单例模式。 介绍 …

单例模式介绍

目录 1 前言 2 单例模式类型 2.1 饿汉式: 2.2 懒汉式: 2.2.1 双重检查锁 2.2.2 volatile防止指令重排 2.3 静态内部类 3 破坏单例 1 前言 单例模式是指在内存中有且只会创建一次对象的设计模式,在程序中多次使用同一个对象且作用相同…

单例模式详解(附常见的7种单例模式源码)

单例模式(Singleton Pattern):保证一个类仅有一个对象,并提供一个访问它的全局访问点。(Ensure a class only has one instance,and provide a globe point of access to it.) 常见应用场景: Windows的Task Manager(…

设计模式(一)—单例模式(附Java代码)

单例模式(Singleton Pattern):采取一定的方法保证在整个的软件系统中,对于某个类只能存在一个对象实例,并且该类只提供一个取得其实例对象的方法。 比如Hibernate的SessionFactory,它充当数据存储源的代理,…

线程的运行状态

不管是多线程还是多进程,实际上都不太可能一直占用CPU资源,所有多线程的几种状态一定要掌握。 多线程的状态如下图: 所有的系统费资源是有限的,不管是多线程还是多进程都必须在执行一段时间后让出资源,交由其他的线程…

一条SQL语句统计总数及各状态数

需求:共有协议X份,已签XX份,待签X份 sql: select count(1) 总记录数,sum(case when XY_STATUS1 then 1 else 0 end)待签,sum(case when XY_STATUS2 then 1 else 0 end)已签 from YG.T_ZHGL 结果: count(1):所有数据&#xff…

线程的执行状态

1,创建: 当创建好线程对象的时候,也就是new Thread类或者是new Thread子类的时候。此时称为创建状态 2,就绪: 当线程对象调用了start()方法,开启线程了的时候,此时的线程已经开启了&…

Java线程线程的状态

1、线程的状态 线程有六种状态:分别如下 ① NEW(新建) 线程刚被创建,但是并未启动。还没调用start方法 ② Runnable(可运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统…

Java多线程批量执行sql

当遇到大sql批量导入时几十万上百万数据,使用plsql执行等都是非常的慢。因此开发一套自定义线程池处理sql: 1,线程代码 import java.util.ArrayList;/*** ClassName: com.ai.order.esb.yulang.tools.handle* Description: TODO* version: v1…

一条SQL语句是如何执行的?

大家六一儿童节好呀! 接下来的一段时间内,将带领大家一同探索MySQL的奥妙,加油吧!我们。 下面进入正题:一条SQL语句是如何进行的? 对于这个问题,我想将其分为两个问题来回答,分别是…

mysql 查看线程状态

show full PROCESSLIST 打开两个查询窗口,在A窗口执行一个查询时间较长的sql,在B窗口使用show full PROCESSLIST,可以看到A中执行的sql时间。 sleep表示没有操作,query表示正在查询。

线程状态总结

目录 文章目录 前言 一、线程状态图解 二、线程的几种状态 及线程过程 1.线程的几种状态 2.线程过程 总结 前言 总结了在华清远见这段时间所学的线程相关的知识点,文章记录了线程的几种状态及线程的过程 提示:以下是本篇文章正文内容,下面案…

线程状态

原文:https://mp.weixin.qq.com/s/GsxeFM7QWuR--Kbpb7At2w 人类为了利用好自己的时间,经常会同时做多件事情,比如上厕所时刷手机,开车时听新闻... 对于自己尚且如此,对计算机也不能闲着。为了最大化的提升机器利用率&…

一条SQL语句的执行过程

摘要 本文站在后端开发的角度,讲述一条SQL从客户端发送到MySQL服务器进行处理,并将结果返回给客户端的过程。这个过程中涉及的操作会在后面的文章中做详细的分析。 连接建立 我们通常使用ORM框架来生成SQL语句,在发送SQL语句给MySQL服务器…

多线程执行sql报错处理

pymysql多线程访问数据库报错:Packet sequence number wrong - got 7 expected 2 原文:https://www.cnblogs.com/heiao10duan/p/9373237.html参考:https://www.jianshu.com/p/60c8e0e440ea原因: 使用了多线程,多线程共…

MySQL - 一条 SQL 语句是如何执行的(SQL执行详解)

前言 天天和数据库打交道,一天能写上几十条 SQL 语句,但你知道我们的系统是如何和数据库交互的吗?MySQL 如何帮我们存储数据、又是如何帮我们管理事务?....是不是感觉真的除了写几个 「select * from dual」外基本脑子一片空白&a…

一、SQL语句执行过程

一、MySQL架构图 MySQL逻辑架构图,可以分为 Server 层和存储引擎层两部分。 Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等&…

线程状态详解

线程的生命周期 new的时候即为创建状态。 调用start即为启动了,启动线程后就变为就绪状态, 就绪之后等待CPU的调度,CPU调度完之后,就进入了运行状态。 运行状态运行sleep方法时会进入阻塞状态,进入阻塞状态有非常多…

一条 SQL 语句是如何执行的

1. select 语句执行过程 一条 select 语句的执行过程如上图所示 1、建立连接 连接器会校验你输入的用户名和密码是否正确,如果错误会返回提示,如果正确,连接器会查询当前用户对于的权限。连接器的作用就是校验用户权限 2、查询缓存 MySQL…