当前位置:网站首页>How many ways do you know the singleton pattern?
How many ways do you know the singleton pattern?
2022-08-03 00:26:00 【The horse small crumbs】
I've been brushing for a whileSpring的书籍.在看SpringAnd often see“单例”,“工厂”这些字样.
所以,Let’s talk about the singleton and factory design patterns first.,These two patterns are also very common,I see a lot of face scriptures will encounter these two modes~
本文主要讲解单例设计模式,如果有错的地方希望能多多包涵,并不吝在评论区指正!
一、单例模式概述
Singleton pattern definition is simple:Create an instance of a class,So called singleton!
So when do we use the singleton pattern??
Since then we think about in a class can only create an instance,Then it can be said that this isThe state of the class is independent of the object的了.
频繁创建对象、Managing objects is a resource-intensive business,We just need to create an object to use it!
学过Java Webof students may know:
Servlet是单例的
Struts2是多例的
SpringMVC是单例的
Since multiple instances are frequently creating objects、Need to manage object,那Struts2Why do many cases??
主要由于设计层面上的问题,Struts2是基于Filterinterception,ognlThe engine was injected to variable.So it has to be designed to be multi-instance~
Can do it with one object without instantiating multiple objects!This can reduce our space and memory overhead~
It is possible that some people will think again:我们使用静态类.doSomething()
and calling a method using a singleton object效果是一样的啊.
没错,效果就是一样的.使用
静态类.doSomething()
体现的是基于对象,And use the singleton design pattern is reflected面向对象.
二、Write a singleton code
Writing code for the singleton pattern is actually quite simple,in three steps:
将构造函数私有化
In the interior of the class instance is created
提供获取唯一实例的方法
2.1饿汉式
根据上面的步骤,我们就可以Create singleton objects easily了.
public class Java3y {
// 1.将构造函数私有化,不可以通过new的方式来创建对象
private Java3y(){}
// 2.在类的内部创建自行实例
private static Java3y java3y = new Java3y();
// 3.提供获取唯一实例的方法
public static Student getJava3y() {
return java3y;
}
}
We call this code:“饿汉式”:
Object is created as soon as it comes up,如果该实例从始至终都没被使用过,则会造成内存浪费.
2.2简单懒汉式
Since said started to create objects,If it is not used, it will cause a waste of memory:
那么我们就设计用到的时候再创建对象
public class Java3y {
// 1.将构造函数私有化,不可以通过new的方式来创建对象
private Java3y(){}
// 2.1先不创建对象,Create it when you need it
private static Java3y java3y = null;
// 2.1call this method,Proved to be used
public static Java3y getJava3y() {
// 3. If this object is referenced asnull,we create and return
if (java3y == null) {
java3y = new Java3y();
}
return java3y;
}
}
The above line of code does not work??OK in a single-threaded environment,It doesn't work in a multithreaded environment!
要解决也很简单,我们Just lock it了:
2.3双重检测机制(DCL)懒汉式
The above method of directly adding locks to the method is not good enough.,因为在The lock with a built-in methodPerformance will be lower in multi-threaded environment,所以我们可以narrow the scope of the lock.
public class Java3y {
private Java3y() {
}
private static Java3y java3y = null;
public static Java3y getJava3y() {
if (java3y == null) {
// narrow the scope of the lock,提高性能
synchronized (Java3y.class) {
java3y = new Java3y();
}
}
return java3y;
}
}
Does the above code work???不行,Because although the lock is added,但还是有two objects may be created出来的:
线程A和线程B同时调用
getJava3y()
方法,他们同时判断java==null
,得出的结果都是为null,所以进入了if代码块了此时线程A得到CPU的控制权-->进入同步代码块-->创建对象-->返回对象
线程A完成了以后,此时线程B得到了CPU的控制权.同样是-->进入同步代码块-->创建对象-->返回对象
很明显的是:Java3y类Back to more than one instance!所以上面的代码是不行的!
Some students may think I am no big talk than,Ming lock doesn't work?我们来测试一下:
public class TestDemo {
public static void main(String[] args) {
// 线程A
new Thread(() -> {
// 创建单例对象
Java3y java3y = Java3y.getJava3y();
System.out.println(java3y);
}).start();
// 线程B
new Thread(() -> {
// 创建单例对象
Java3y java3y = Java3y.getJava3y();
System.out.println(java3y);
}).start();
// 线程C
new Thread(() -> {
// 创建单例对象
Java3y java3y = Java3y.getJava3y();
System.out.println(java3y);
}).start();
}
}
可以看到,object to print不单单只有一个的!
Great programmer thought again:进入同步代码块时To judge whether the object exists is steady!
所以,有了下面的代码
public class Java3y {
private Java3y() {
}
private static Java3y java3y = null;
public static Java3y getJava3y() {
if (java3y == null) {
// narrow the scope of the lock,提高性能
synchronized (Java3y.class) {
// Judge again whethernull
if (java3y == null) {
java3y = new Java3y();
}
}
}
return java3y;
}
}
Actually not stable!There will be reordering issues here:
Originally wanted to test the effect of the reordering problem,Hasn't been tested~~~If you have relevant test code, you can tell me how to measure it….
Is also very simple to solve,加上我们的volatile关键字就可以了,volatile有内存屏障的功能!
所以说,完整的DCL代码是这样子的:
public class Java3y {
private Java3y() {
}
private static volatile Java3y java3y = null;
public static Java3y getJava3y() {
if (java3y == null) {
// narrow the scope of the lock,提高性能
synchronized (Java3y.class) {
// Judge again whethernull
if (java3y == null) {
java3y = new Java3y();
}
}
}
return java3y;
}
}
再说明:
2.4静态内部类懒汉式
还可以使用The clever way of static inner classes来实现单例模式!它的原理是这样的:
when any thread第一次调用
getInstance()
时,都会使SingletonHolder被加载和被初始化,此时静态初始化器将执行Singleton的初始化操作.(Initialized when called!)Initialize static data,JavaProvides thread safety guarantees.(So don't need any synchronization)
public class Java3y {
private Java3y() {
}
// Using inner classes to implement lazy loading
private static class LazyHolder {
// 创建单例对象
private static final Java3y INSTANCE = new Java3y();
}
// 获取对象
public static final Java3y getInstance() {
return LazyHolder.INSTANCE;
}
}
静态内部类这种方式is highly recommended的!A lot of people did not experience the singleton pattern of all don't know how this kind of writing,This way of writing is optimized and efficient!
2.5枚举方式实现
Using the enumeration is very simple:
public enum Java3y3y {
JAVA_3_Y_3_Y,
}
What's the benefit of that??Implemented by enumeration:
简单,直接写就行了
防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候(安全)!
This is also recommended!
三、总结
In general, the singleton pattern is written as5种:
饿汉式
简单懒汉式(lock in method)
DCL双重检测加锁(进阶懒汉式)
静态内部类实现懒汉式(最推荐写法)
枚举方式(最安全、简洁写法)
边栏推荐
- 字节内部技术图谱 惊艳级实用
- LeetCode 2360. 图中的最长环 基环树找环+时间戳
- I interviewed a 985 graduate, and I will never forget the expression when answering the "performance tuning" question
- 主成分分析(PCA)
- CS5213芯片|HDMI to VGA转换头芯片资料分享
- golang刷leetcode:道路的最大总重要性
- X 2 Earn必须依靠旁氏启动?GameFi的出路在哪?(下)
- win10安全中心设置不扫描某个文件夹的方法
- Win10怎么开启自带的游戏录屏功能?
- ECCV 2022 | ByteTrack: 简单高效的数据关联方法
猜你喜欢
Zabbix 5.0 Monitoring Tutorial (2)
搭建Spark开发环境(第二弹)
[C题目]力扣142. 环形链表 II
Adobe官方清理工具Adobe Creative Cloud Cleaner Tool使用教程
HCIP--路由策略实验
I interviewed a 985 graduate, and I will never forget the expression when answering the "performance tuning" question
如何抓住NFT、元|宇|宙新趋势?
PyRosetta 安装方法之Conda安装
典型相关分析CCA计算过程
工厂模式理解了没有?
随机推荐
JMeter的基本使用
Flink-SQL
30天啃透这份Framework 源码手册直接面进大厂
Do you understand the factory pattern?
千人优学 | GBase 8s数据库2022年6月大学生专场实训圆满结束
【DEBUG】ImportError: Unable to import required dependencies: numpy: DLL load failed: 找不到指定的模块。
【目标检测】YOLOv5:640与1280分辨率效果对比
Adobe官方清理工具Adobe Creative Cloud Cleaner Tool使用教程
二叉搜索树的实现
Swin Transformer 论文精读,并解析其模型结构
[C题目]力扣234. 回文链表
Command line startup FAQs and solutions
SublimeText3 安装、配置项、包管理、常用必备插件、常用快捷键以及修改
主成分分析(PCA)
最近火爆朋友圈的“广告电商”,核心商业模式是什么,广告收入真实靠谱吗?
FRED应用:激光二极管光源耦合到光纤的仿真
解道6-编程技术3
golang刷leetcode: 小于等于 K 的最长二进制子序列
IP协议(网际协议)
【干货】分库分表最佳实践