浅析Java单例设计模式,自写demo,简单易懂

单例模式Demo 单例模式的示例程序,详见博客http://blog.youkuaiyun.com/xingjiarong?viewmode=contents 立即下载

单例模式特点:

1、构造器私有

2、在一个Java应用程序中,可保证只有一个实例对象

3、只提供一个供外界调用的getInstance()方法

单例模式优点:

1、减少某些对象的频繁创建,降低系统开销和内存占用

2、外部调用不使用new关键字,降低系统内存的使用频率

3、对于特殊的类,在系统中只能存在一个实例,否则系统无法正常运行,比如Controller

这里简单介绍两种实现方式

饿汉式(线程安全)

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:07
 * @description: 单例模式(饿汉式)
 **/
public class Singleton {
    //创建实例
    private static Singleton instance = new Singleton();

    //私有构造器
    private Singleton(){
    }

    //获取实例的静态方法
    public static Singleton getInstance(){
        return instance;
    }

}

 实例对象在类被加载的时候就已经完成初始化,外界调用拿到的都是这个唯一的实例对象

懒汉式

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 单例模式(懒汉式)
 **/
public class Singleton {
    //声明一个变量
    private static Singleton instance;

    //私有构造器
    private Singleton(){
    }

    //获取实例的静态方法
    public static Singleton getInstance(){
        //如果是首次调用,实例对象还没有被创建,就需要创建,否则都是返回已经创建过的那个对象
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }

}

对比饿汉式可见,实例对象在类被加载的时候并没有进行创建,在首次调用的时候才被创建,以后再被调用,返回的也是那个唯一的实例对象。

在多线程情况下,这种写法存在线程安全问题,比如:线程A在执行完if判断条件后进入阻塞状态,此时并没有进行对象创建,此时线程B来了,在执行完if条件后直接进行对象创建,等线程A恢复运行状态后也会进行对象创建,这个时候就不符合单例模式了,即出现了线程不安全的问题。

解决方案:在获取实例的静态方法上加synchronized关键字,即加锁

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 单例模式(懒汉式)
 **/
public class Singleton {
    //声明一个变量
    private static Singleton instance;

    //私有构造器
    private Singleton(){
    }

    //获取实例的静态方法
    public static synchronized Singleton getInstance(){
        //如果是首次调用,实例对象还没有被创建,就需要创建,否则都是返回已经创建过的那个对象
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }

}

简单粗暴,可达到我们的目的,但是每次获取实例对象都要有加锁操作,影响系统性能。

改进后的方案:双重检查

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 单例模式(懒汉式)
 **/
public class Singleton {
    //声明一个变量
    private static Singleton instance;

    //私有构造器
    private Singleton(){
    }

    //获取实例的静态方法
    public static synchronized Singleton getInstance(){
        //第一次检查
        if (instance == null){
            //获取锁
            synchronized (Singleton.class){
                //第二次检查
                if (instance==null){
                    //两次检查都确定没有已存在的实例对象,这才进行对象的创建操作
                    instance = new Singleton();
                }
            }
            
        }
        return instance;
    }

}

这样不必每次获取实例对象的时候都进行加锁操作,只有在第一次创建对象的时候才进行加锁操作,提高了系统性能。

但是,即使这样有可能会出现。因为 instance = new Singleton()这行代码在JVM中是两个操作,赋值和初始化实例,但JVM并不保证这两个操作的顺序,有可能JVM给新对象分配了空间,直接赋值给instance变量,然后才去做初始化实例操作。比如下面这种情况

1,A,B两个线程都进入第一个if条件

2,A线程先抢到锁进入到synchronized代码块,执行了instance = new Singleton()这行代码,然后释放锁,此时有可能JVM只给实例对象分配了空白的内存空间,并没有执行初始化操作

3,B线程抢到锁,进入到synchronized代码块,第二次判断的时候发现instance不是null,直接返回使用却发现得到的对象还没有被初始化,于是出现了问题。

再次改进:使用volatile关键字修饰声明的成员变量instance

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 12:22
 * @description: 单例模式(懒汉式)
 **/
public class Singleton {
    //声明变量,被volatile修饰
    private volatile static Singleton instance;

    //私有构造器
    private Singleton(){
    }

    //获取实例的静态方法
    public static synchronized Singleton getInstance(){
        //第一次检查
        if (instance == null){
            //获取锁
            synchronized (Singleton.class){
                //第二次检查
                if (instance==null){
                    //两次检查都确定没有已存在的实例对象,这才进行对象的创建操作
                    instance = new Singleton();
                }
            }

        }
        return instance;
    }

}

volatile关键字作用:通过volatile修饰的变量,不会被线程本地缓存,所有线程对该对象的读写都会第一时间同步到主内存,从而保证多个线程间该对象的准确性。

这个写法已经比较完美了,既能保证安全的创建出唯一实例,又不会对系统性能有太大影响。

不过,还有更优的写法:静态内部类实现(懒汉式)

​
/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 15:17
 * @description: 单例模式
 **/
public class Singleton {

    //私有构造器
    private Singleton() {
    }

    //静态内部类声明实例
    private static class SingletonFactory{
        private static Singleton instance = new Singleton();
    }

    //获取实例的静态方法
    public static Singleton getInstance(){
        return SingletonFactory.instance;
    }
    
}

​

使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance()方法的时候,JVM能够保证创建出唯一的实例对象,并且这个实例对象是已经被初始化完成的,就解决了上面的线程安全问题

最后一种实现单例的写法也很完美,代码最简洁

通过枚举(饿汉式)

/**
 * @author: xuzhilei6656
 * @create: 2021-12-12 15:33
 * @description: 单例模式
 **/
public enum Singleton {

    //代表一个Singleton实例
    INSTANCE;
}

通过枚举来实现单实例代码更加简洁,而且JVM从根本上保证实例对象的唯一性,是更简洁、高效、安全的实现单例的方式

以上是个人学习时敲的demo,有不正确的地方,还请谅解,希望对朋友们有帮助,谢谢!

用java写界面最简单的一个demo 立即下载

相关推荐

【Unity】ABB CRB 15000 外部引导运动实战:从配置到实时控制

本文详细介绍了ABB CRB 15000协作机器人的外部引导运动(EGM)功能在Unity环境中的实战应用。从RobotStudio配置到Unity实时通信架构,再到EGM运动控制技巧和问题排查,全面解析如何实现机器人的高精度实时控制。通过实际案例展示EGM技术在精密装配等场景中的显著效果,帮助开发者快速掌握这一先进技术。

weixin_29057695的博客 444

BlogTest1

常见数据结构题 SparseArray SparseBooleanArray = HashMap 常见设计模式 单例Builder观察者工厂代理适配器 3种常见的单例写法 饿汉式(静态常量)[可用] public class Singleton { private final static Singleton INSTANCE = new

zz_itheima的博客 488

《python神经网络编程》程序实现

《python神经网络编程》程序实现 通过对这本书的学习,结合这本书的内容: 完成了以下代码: 其中NN.py实现了一个类,这个类可以完成神经网络的初始化,训练以及输入数据并得出结果。 而run.py则是对神经网络类的使用 NN.py: import numpy import scipy.special #神经网络类的实现 class neuralNetwork: #构造函数初始化类 def __init__(self,inputnodes,hiddennodes,outputnodes

ms8617484的博客 618

使用Java实现单例模式

很明显,虽然benzCar和benzCar1的属性都是"奔驰"和"小叮当",但是他们的hashcode却不相等,这意味着,在计算机(jvm)看来,实际上他们创建了两个对象.占用了两份内存.实际小叮当只有一辆车,计算机模型和真实世界的模型不一致了.会导致程序出现问题.如何解决这个问题呢?

m0_59996263的博客 889

避坑指南:AUTOSAR FlashDriver操作DFlash模拟EEPROM时,你最容易忽略的5个细节

本文深入探讨了AUTOSAR FlashDriver在DFlash模拟EEPROM操作中最容易被忽视的五大细节问题,包括地址合法性检查、操作时序控制、并发访问冲突、电源稳定性管理和寿命管理。通过实际项目案例和工程化解决方案,帮助开发者避免常见陷阱,提升汽车电子控制单元(ECU)的可靠性和稳定性。

weixin_42741930的博客 245

Flutter for web 首次加载过慢问题优化

Flutter web 加载慢优化

Bright_TY的专栏 7834

Java环境搭建及Demo测试

Java环境搭建

qq_22031999的博客 3289

Miniconda入门:在CentOS上的安装、基本操作、目录结构、卸载

Miniconda是一个 免费的 轻量级的 conda安装程序 它只包含conda、Python、pip、zlib等基础的文件和依赖包 使用conda install命令可从Anaconda存储库中安装额外的conda包 简介 下载 安装 基本操作 虚拟环境的操作 包的操作 目录结构 卸载

ArYe 1万+

(一)JAVA设计模式23种设计模式之单例模式实例demo

单例模式实现由两种,一种是饿汉模式,见Singleton1类。 另一种是懒汉模式(延迟加载)。 懒汉模式又可分为代码同步块实现,见Singleton4类。 懒汉模式又可分为静态内部类实现,见Singleton5类。 懒汉模式又可分为枚举方式实现,见Singleton6类。 执行主函数 package singleton_method_mod; import org.junit.Test; /** * 单例模式 * 单例模式(Singleton Pattern)是 Jav...

绝对秋香 521

YOLOv10改进,YOLOv10二次创新C2f结构采用WTConv卷积(感受野的小波卷积),ECCV 2024

WTConv 的核心思想是通过结合卷积神经网络(CNN)的强大特征提取能力与小波变换的多尺度特性,来实现大感受野的卷积操作,同时避免传统大卷积核带来的参数爆炸问题。传统的卷积操作通过滑动小窗口在图像上逐步执行局部特征提取,感受野的大小直接取决于卷积核的尺寸。随着卷积核的增大,参数量呈指数增长,导致网络训练效率降低、计算资源消耗增加。为解决这些问题,WTConv 提出了在小波域中执行卷积操作的策略。小波变换是一种常用于信号处理的技术,能够将信号分解为不同频率成分。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1022

ASProxy64.dll导致jetbrains家的IDE都无法打开。

摘要:在Windows11系统中,JetBrains IDE无法启动,报错指向ASProxy64.dll文件。该第三方DLL被注入到JVM原生层,导致内存访问冲突(错误代码0xc0000005)。经排查发现此文件来自Astrill软件。解决方案为卸载Astrill后重启电脑,问题得以解决。该案例表明第三方DLL注入可能影响IDE正常运行,卸载相关软件是最直接的解决方法。(149字)

猿小白的博客 935

设计模式3——单例模式Singleton

参考链接: 单例模式-菜鸟教程:https://www.runoob.com/design-pattern/singleton-pattern.html 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象...

weixin_33711641的博客 153

掌握 Unity 中的状态机:综合指南

最后,将拥有一个由状态机驱动的功能齐全的播放器控制器,可以集成到自己的项目中。此外,状态机有助于实现复杂的人工智能、玩家控制、动画系统等,从而形成更强大、更灵活的游戏架构。状态机是计算机科学和游戏开发中的一个基本概念,它通过定义一组有限的状态及其之间的转换来模拟实体的行为。你可以定义常见的状态行为,例如 Enter、Update 和 Exit 方法,确保整个状态机架构的一致性和连贯性。由于前面提到的状态类扩展了 BaseState 类,因此我们可以为具有不同状态的不同对象创建单独的类。

yolo模型训练找我,AI游戏合作找我 1449

iBATIS SQLMap配置Demo浅析

iBATIS SQLMap配置Demo浅析转载自:http://developer.51cto.com/art/200907/138627.htmiBATIS SQLMap配置Demo向你介绍iBATIS SQLMap的具体配置以及实例。 在Spring的jpestore中,数据持久层用到了iBATIS SQLMaps,这里写一个iBAT

qqzhuyuehe的专栏 1191

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

arthas的核心原理浅析

Arthas 等 Java 诊断工具核心原理浅析 项目地址 看了会 arthas 源码,结合资料 。用一个小 demo 展示下 arthas 的核心实现 java instrument agent + ASM 新建一个普通的java项目,包结构如下 三个包 : target 目标类 模拟平时要维护的服务 client 客户端 模拟arthas客户端 agent 代理程序 客户端挂载target 再执行 target 的jar包 ,提供修改字节码等功能 主要执行流.

我是个农民的博客 3128

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

springboot浅析

实际上springboot就是一个给我们提供了快速搭建使用spring的一种方式,让我们省去了繁琐的xml配置。为什么无需进行大量的xml配置,就是因为springboot是基于约定优于配置的思想,简单来说就是遵循约定。**starter是什么?**我们可以把它理解成为一个可插拔式的插件,有了这些starter我们使用某些功能的时候,就不需要去关注各种依赖的处理,不需要我们去配置那些复杂的配置信息,由springboot自动通过classpath路径下的类发现我们需要的bean,并注入相应的bean。

rita_0567的博客 1120

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Spring前瞻——浅析Java的动态代理模式

Spring的两个主要思想就是IOC和AOP。其中最重要的AOP思想使用的就是java的动态代理模式,学习这种底层原理对于我们理解AOP思想很重要。 学习动态代理模式之前,我们要先学习代理模式。 代理模式 定义 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 代理模式(Proxy P...

晃在云淡风轻 323

Java NIO浅析

Java NIO浅析 2016年11月04日作者: 王烨文章链接9969字20分钟阅读 NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。 那么NIO的本质是什么样的呢?它是怎样与事件模型结合来解放线程、提高...

大隐隐于野 274

Java中文乱码浅析及解决方案

Java中文乱码浅析及解决方案

weixin_43860634的博客 2370

Java抽象语法树AST浅析与使用

Java抽象语法树AST浅析与使用概述作用Java项目模型对象AST模型对象AST试图具体使用 概述 抽象语法树(Abstract Syntax Tree, AST)是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的结构,树的每个节点ASTNode都表示源码中的一个结构。Eclipse java的开发工具(JDT)提供了Java源代码的抽象语法树AST。抽象语法树就像是java文件的do...

peng425的博客 3万+

COM组件浅析(一) - 使用Java操作Adobe Illustrator

COM组件浅析(一) - 使用Java操作Adobe Illustrator一、下载Jacob二、创建JacobDemo maven工程,引入jacob依赖1. 创建工程2. 引入jacob依赖3. 在pom.xml中引入jacob.jar三、在代码中操作Adobe Illustrator四、Jacob中的Dispatch简单介绍 ​  在Windows下,使用Java操作Adobe Illustrator(下称“AI”),需要通过JNI技术调用C++来实现。在本地安装好AI后,AI会在注册表注册自己的CO

weixin_37504415的博客 1928

jni 调用java接口_深入浅析jni中的java接口使用

JNI中的java接口使用项目需求,需要在c++函数中监听相应的状态,并在java端进行一些列的处理。这个需要在JNI中写一个subscriber,注册后在需要的地方进行引入使用。目录结构初始化是AS上的c++工程文件,这边先暂时实现简单的demo,CdemoActivity是NativeActivity的实现,我们暂时别管,因为实现是c++层控制的,有兴趣可以去百度下主要涉及jnicallbac...

weixin_42100129的博客 460

java不把密码存储在浏览器_浅析博客园的保存密码并自动登录, 然后自己写一个demo...

现在的网站基本上都有保存密码并自动登录的功能, 那么密码到底保存在哪里呢? 你会发现, 同一个网站, 如果换一台电脑或者换一个浏览器那就需要重新输入用户名和密码, 从这里可以看出, 密码是保存在浏览器的. 今天就来分析一下博客园的登录并自己写一个demo. 密码是保存在浏览器的cookie中的, 那什么叫cookie呢? w3cshool中有这样的定义:cookie 是存储于访问者的计算机中的变...

weixin_39517241的博客 219

Java 反射浅析

Java 反射浅析 目录 Java 反射浅析 反射的意义 反射的基本运用 获取class对象 创建获取到的Class类对象的实例 获取类的方法 获取类的成员变量 调用类的方法 Simple Demo 反射原理浅析 1. 反射的意义 Java反射机制是指在运行状态,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用...

weixin_42108260的博客 187

Java构造器浅析

Java构造器 问题引出 1.先看一段简单创建对象的例子: public class constructTest { public static void main(String[] args) { Index t = new Index(); t.dance(); } } class Index{ public void dance(){ System.out.prin...

沐雨橙风 187
下一篇: 数据结构与算法之最大优先队列
海深不见鲸
博客等级 码龄6年 7粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值