当前位置:网站首页>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双重检测加锁(进阶懒汉式)
静态内部类实现懒汉式(最推荐写法)
枚举方式(最安全、简洁写法)
边栏推荐
猜你喜欢
随机推荐
【DEBUG】ImportError: Unable to import required dependencies: numpy: DLL load failed: 找不到指定的模块。
饥荒联机版Mod开发——制作简单的物品(三)
golang刷leetcode:我能赢吗
JMeter的基本使用
什么是幂等
golang 刷leetcode:将字符串翻转到单调递增
典型相关分析CCA计算过程
终于明白:有了线程,为什么还要有协程?
成功解决TypeError: can‘t multiply sequence by non-int of type ‘float‘
最近火爆朋友圈的“广告电商”,核心商业模式是什么,广告收入真实靠谱吗?
总结嵌入式C语言难点(2部分)
Do you understand the factory pattern?
如何理解 swing 是非线程安全 (原创)
js how to get the browser zoom ratio
如何抓住NFT、元|宇|宙新趋势?
y85.第四章 Prometheus大厂监控体系及实战 -- prometheus告警机制进阶、pushgateway和prometheus存储(十六)
【干货】分库分表最佳实践
无线振弦采集仪远程修改参数的方式
iptables、firewalld的使用
apache calcite中关于model文件配置