概述

单例模式是一种创建者模式。当我们需要确保系统中某个类仅能存在一个对象时,比如:全局信息类例如当项目启动时我们将一个配置文件读取为一个Config类的实例从而在业务逻辑中通过操作对象读取配置、无状态的工具类仅需一个实例进行复用即可,也就是当该对象仅需一个实例即可或处于安全考虑而做出的限制并且反复创建该实例会消耗系统资源,此时可以使用单例模式。

实现方法

在实现一个单例类时,由于涉及到类加载、对象属性的创建、对象属性的访问等问题,需要考虑到对象创建时间、创建与赋值的方式、线程安全、阻止反射与对象序列化造成的被多例等情况。

Eager 饿汉式

饿汉式是最简单的单例模式,类中的对象属性在类加载时就被初始化,由于JVM加载类时保证单线程,所以避免了线程问题,但eager加载方式造成即使运行过程中全程未使用类该类也会被加载,造成不必要的资源浪费。

public class Singleton {

    private static Singleton singleton = new Singleton();

    private Singleton {}

    public static Singleton getInstance() {
return singleton;
}
}

等同代码

public class Singleton {

    private static Singleton singleton;

    static {
singleton = new Singleton();
} private Singleton {} public static Singleton getInstance() {
return singleton;
}
}

Lazy 懒加载

懒加载即在使用时对单例类进行实例化,但简单的懒加载未考虑线程安全问题,在getInstance()方法中,若两个线程同时进入实例对象等于nullif语句中,对象将会被实例化两次从而违背单例模式的初衷。

//  线程不安全的懒加载单例类代码
public class Singleton { private static Singleton singleton; private Singleton() {} public static Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
// 重量级锁线程安全的懒加载单例类实现
public class Singleton { private static Singleton singleton; private Singleton() {} public static synchronized Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
// 方法内部锁线程安全的懒加载单例类实现(双重检查)
public class Singleton { // 由于实例化对象非原子操作,所以加volatile
private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() {
// 第一次判断让实例构造完成后能并发执行
if(singleton == null) {
synchronized (Singleton.class) {
// 第二次判断防止第一次判断同时进入多个线程
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
// 静态内部类懒汉式写法
public class Singleton { private Singleton() {} // 使用了静态内部类,让JVM在类加载也就是内部类被Singleton.getInstance()方法内调用时时为我们初始化
private static class SingletonInstance {
private static final Singleton singleton = new Singleton();
} public static Singleton getInstance() {
return SingletonInstance.singleton;
}
}

Enum 枚举式

枚举式就是用java中枚举类的形式构造的单例类,枚举式在保证能懒加载线程安全(枚举对象是以static形式初始化,JVM保证线程安全)的同时,由于java中规定了在枚举对象序列化时仅输出name,而反序列化时使用name查找对象,从而实现了单例而非被破坏。在反射中,由于newInstance()在用户试图创建enum类型的对象时会检查从而报错,所以十分安全。

// 枚举式实现Resource的单例,通过Something.INSTANCE.getInstance()即可访问
class Resource{ } public enum Something { INSTANCE; private Resource instance; Something() {
instance = new Resource();
} public Resource getInstance() {
return instance;
}
}

总结

结合多方因素,能同时实现懒加载、线程安全、阻止序列化反序列化与反射破坏单例就是最佳的枚举式单例模式实现。

Java学习笔记 - 单例模式的更多相关文章

  1. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

  2. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  3. 0035 Java学习笔记-注解

    什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...

  4. Java学习笔记(04)

    Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...

  5. 0032 Java学习笔记-类加载机制-初步

    JVM虚拟机 Java虚拟机有自己完善的硬件架构(处理器.堆栈.寄存器等)和指令系统 Java虚拟机是一种能运行Java bytecode的虚拟机 JVM并非专属于Java语言,只要生成的编译文件能匹 ...

  6. 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用

    垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...

  7. 0028 Java学习笔记-面向对象-Lambda表达式

    匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...

  8. 0025 Java学习笔记-面向对象-final修饰符、不可变类

    final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...

  9. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  10. Java学习笔记-多线程-创建线程的方式

    创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...

随机推荐

  1. 饿了么EMonitor演进史

    简介: 可观测性作为技术体系的核心环节之一,跟随饿了么技术的飞速发展,不断自我革新. 序言 时间回到2008年,还在上海交通大学上学的张旭豪.康嘉等人在上海创办了饿了么,从校园外卖场景出发,饿了么一步 ...

  2. KubeVela 1.1 发布,开启混合环境应用交付新里程碑

    ​简介: KubeVela 作为一个开箱即用.面向现代微服务架构的应用交付与管理平台,今天正式发布了 1.1 版本,以更加用户友好和完善的功能集,开启了"让混合环境应用交付更加简单高效&qu ...

  3. dotnet 5 让 WPF 调用 WindowsRuntime 方法

    本文告诉大家在 dotnet 5 里,如何使用 WinRT 加上 Microsoft.Windows.SDK 的辅助来调用 WindowsRuntime 方法.当前是 2021.10 此时的 Wind ...

  4. MSIL 静态类在 IL 定义上和非静态类的差别

    本文来聊聊 MSIL 的基础知识,给一个 C# 的类标记了 static 之后和标记 static 之前,生成这个类的 IL 代码有什么不同 如以下的代码是一个默认的控制台程序 class Progr ...

  5. 1.权限控制RBAC

    官方参考地址:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/#privilege-escalation-prev ...

  6. LVGL学习资料

    一.资料整理 官网:https://lvgl.io/ 使用手册: 官方的使用手册是英文版的,百问网将其翻译成中文版的文档.地址如下: 官方使用文档:https://docs.lvgl.io/maste ...

  7. netcore5下ocelot网关简单使用

    1.新建aspnetcoremvc项目,带home控制器的就可以了,测试用能启动就行,代码无需做任何更改. 2.新建空的aspnetcoremvc项目,做如下更改: 1..  2.. 3..  4.. ...

  8. ADV7123驱动VGA显示色条

    VGA显示色条-基于ADV7123 用ADV7123代替权电阻网络,执行数模转换,差别在于rgb都变成8位,显示的色彩更多.控制端口多了3个:像素时钟,复合同步信号(不用就置0),消隐信号. 相对权电 ...

  9. 推荐一款轻量级堡垒机系统让你防护“rm -rf 删库跑路”

    大家好,我是 Java陈序员. 我们在开发工作中,会经常与服务器打交道,而服务器的资源又是十分宝贵,特别是服务器里面的数据资源. 但是,偶尔会经常因为疏忽而导致服务器数据资源丢失,给自己和公司带来巨大 ...

  10. 集群监管-USDP(智能大数据平台)

    UCloud Smart Data Platform(简称 USDP),是 UCloud 推出的智能化.轻量级.适用于私有化部署至客户本地的大数据基础服务平台,通过自研的 USDP Manager 管 ...