Java学习笔记 - 单例模式
概述
单例模式是一种创建者模式。当我们需要确保系统中某个类仅能存在一个对象时,比如:全局信息类例如当项目启动时我们将一个配置文件读取为一个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()方法中,若两个线程同时进入实例对象等于null的if语句中,对象将会被实例化两次从而违背单例模式的初衷。
// 线程不安全的懒加载单例类代码
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学习笔记 - 单例模式的更多相关文章
- Java学习笔记4
Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
- Java学习笔记(04)
Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...
- 0032 Java学习笔记-类加载机制-初步
JVM虚拟机 Java虚拟机有自己完善的硬件架构(处理器.堆栈.寄存器等)和指令系统 Java虚拟机是一种能运行Java bytecode的虚拟机 JVM并非专属于Java语言,只要生成的编译文件能匹 ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- Java学习笔记-多线程-创建线程的方式
创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...
随机推荐
- 一图速览 | DTCC 2021大会,阿里云数据库技术大咖都聊了些什么?
简介: 3天9场干货分享,快来收藏吧! 10月18日~10月20日, 由国内知名IT技术社区主办的数据库技术交流盛会--DTCC 2021 (第十一届中国数据库技术大会)在京圆满落幕.大会以&quo ...
- 基于Delta lake、Hudi格式的湖仓一体方案
简介: Delta Lake 和 Hudi 是流行的开放格式的存储层,为数据湖同时提供流式和批处理的操作,这允许我们在数据湖上直接运行 BI 等应用,让数据分析师可以即时查询新的实时数据,从而对您的 ...
- [Cryptocurrency] (XMR) Monero GUI 连接远程节点 操作方式
Monero 官网下载的钱包,在 高级设置 的节点里支持 "本地节点" 和 "远程节点". 本地节点就是同步区块链数据到本地电脑,安全性高,占用空间大. 远程节 ...
- 开源相机管理库Aravis例程学习(四)——multiple-acquisition-signal
目录 简介 例程代码 函数说明 g_main_loop_new g_main_loop_run g_main_loop_quit g_signal_connect arv_stream_set_emi ...
- SAP HANA计算视图
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. 越来越多的SAP用户正在将SAP HANA实施为现有SAP BW的基础和数据库. ...
- R2_ES中数据的存储测试
基本概念:ES(一): 架构及原理 关系数据库 ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns) Elasticsearch ⇒ 索引(Index) ⇒ 类型(Type) ⇒ 文档(Documen ...
- 【进阶篇】基于 Redis 实现分布式锁的全过程
目录 前言 一.关于分布式锁 二.RedLock 红锁(不推荐) 三.基于 setIfAbsent() 方法 四.使用示例 4.1RedLock 使用 4.2setIfAbsent() 方法使用 五. ...
- 4、Linux 网络基础
1.基础命令 hostname:查看或设置当前主机名 route [-n]:查看或设置主机中路由表信息 netstat:查看系统的网络连接状态.路由表.接口统计等信息 常用选项 -a:显示所有-n:以 ...
- LVS负载均衡(5)-- LVS持久连接
持久连接: 持久连接用于实现无论使用任何调度算法,在一段时间内(默认300s ),能够实现将来自同一个地址的请求始终发往同一个RS. 语法格式: ipvsadm -A|E -t|u|f service ...
- google账户配置foxmail和使用foxmail
最近想把邮件分门别类,创建一些个人文件夹,更好的筛选邮件,可以尝试使用foxmail 1. 如果你有google账户,在配置foxmail之前需打开google账户的安全设置 https://myac ...