- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
前言:想必想了解设计模式的各位都是走开发路线的吧,那么既然是走开发路线的,那么设计模式可是一定要好好学哦。因为它是一种思想,将会贯彻到你的开发过程,同时如果你使用的得当的话,那么你的项目将会十分的流畅且亮点丰富。当然这也是开始学之前的一些废话。总之,脚踏实地好好学。
我们得先从设计模式的定义出发。哈哈,不知道你们学习东西的流程是什么。反正我学习的一个流程是先要知道这个东西是什么,然后再知道为什么要学习这个东西,然后就是怎样使用这个东西了。这个是学习东西的一个方法和套路,我们需要总结出自己的一个学习新事物的套路来,这样才能事半功倍。
什么是设计模式?
那么什么是设计模式呢?
通过上述的定义的描述,大家肯定都对设计模式有了一定的初步的印象了,但是要进行深刻理解的话,这样还是不够的,需要之后对各个设计模式的学习理解和消化。
为什么要使用设计模式呢?
我们上面简单的介绍了一下设计模式是什么,为什么要学习设计模式,之后我们将从各个设计模式的使用来进行讲解。记住,设计模式是一种思想,我们一定要尽可能地理解它。当然,如果暂时理解不了的话,也不要灰心,慢慢来消化即可。加油吧,骚年!!!
单例模式(英文名:Singleton Pattern
)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建(所以说如果该类是单例模式的话,那么你使用到的它的每一个对象都是相同的。)
。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
只能创建一个实例的类
单例设计模式分类两种(主要区别在于是否在类加载的时候进行相关单实例对象的创建):
饿汉式
:类加载就会导致该单实例对象被创建
懒汉式
:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
饿汉式 - 方式1
/**
* @author :小肖
* 饿汉式方式1:静态成员变量
* @date :Created in 2022/5/5 14:58
*/
public class Singleton {
// 1. 私有构造
private Singleton() {
}
// 2. 静态成员变量
private static Singleton instance = new Singleton();
// 3. 公有的获取方法
public static Singleton getInstance() {
return instance;
}
}
测试方法
/**
* @author :小肖
* @date :Created in 2022/5/5 15:00
*/
public class Test {
public static void main(String[] args) {
// 获取第一个实例
Singleton instance = Singleton.getInstance();
// 获取第二个实例
Singleton instance1 = Singleton.getInstance();
// 比较两个实例是否相等
System.out.println(instance == instance1);
}
}
输出结果
true
饿汉式 - 方式2
/**
* @author :小肖
* 饿汉式方式2:静态代码块
* @date :Created in 2022/5/5 15:05
*/
public class Singleton {
// 1. 私有构造
private Singleton() {
}
// 2. 私有静态变量
private static Singleton instance;
// 3. 静态代码块进行创建对象
static {
instance = new Singleton();
}
// 4. 公有的获取方式
public static Singleton getInstance() {
return instance;
}
}
总的说明:我们观察上述的代码可以发现,我们是将对应的类的构造方法私有,进而防止外部进行创建该类对象,同时在类内部直接创建好对象,从而使得对象是单例的,但可能创建的方式不同。但不管是使用静态代码块的方式创建对象,还是直接创建对象,它们都是在类加载的时候就进行了相关对象的创建,如果我们之后没有对其进行使用,或者说之后的代码中并未使用到该对象,那么这样加载的对象就是浪费了相关内存的。这也是饿汉式的缺点所在,那么也就引申出了 懒汉式实现方式
。
懒汉式 - 线程不安全
/**
* @author :小肖
* 懒汉式实现
* @date :Created in 2022/5/5 15:23
*/
public class Singleton {
// 1. 私有构造方法
private Singleton() {
}
// 2. 静态成员变量
private static Singleton instance; // null
// 3. 公有获取方法
public static Singleton getInstance() {
if (instance == null) {
return new Singleton();
}
return instance;
}
}
为什么线程不安全呢?
当线程1读取到当前 instance
为 null
的时候,那么此时如果就将 cpu
让出给线程2使用的话,那么此时线程2 读取到的当前 instance
也为 null
,那么就会导致两个线程创建了多个实例对象,所以在多线程环境下是不安全的。
懒汉式 - 线程安全
/**
* @author :小肖
* 懒汉式实现
* @date :Created in 2022/5/5 15:23
*/
public class Singleton {
// 1. 私有构造方法
private Singleton() {
}
// 2. 静态成员变量
private static Singleton instance; // null
// 3. 公有获取方法
public static synchronized Singleton getInstance() {
if (instance == null) {
return new Singleton();
}
return instance;
}
}
虽然这种方式能够解决多线程线程安全问题,但是你要知道 synchronized
是重量级锁,虽然 JVM
底层对它进行了相关的优化,但是还是会带来很大的性能消耗。因为这个方法大多数情况下是读操作,所以只有当需要创建对应的实例对象的时候才需要进行对应的加锁的必要,那么我们可以使用 双重检查锁 + volatile
实现一种更好的单例模式。
懒汉式 - 线程安全(双重检查锁 + volatile)
/**
* @author :小肖
* 懒汉式 双重检查锁 + volatile
* @date :Created in 2022/5/5 15:48
*/
public class Singleton {
// 1. 私有构造
private Singleton() {}
// 2. 静态成员变量
private static volatile Singleton instance;
// 3. 公有获取方式
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
return instance;
}
}
}
return instance;
}
}
这里需要注意,我们为什么要在对应的变量上加 volatile
关键字呢?
因为在多线程的情况下,它还是会造成我们对应的单例对象是空指针的情况,该情况主要是由于虚拟机优化和指令重排造成的。所以说我们可以通过加上 volatile
使得消除这种指令重排。
当然这里还有两种实现单例模式的方式:静态内部类的实现方式、枚举的实现方式
。这里我就不一一介绍了。
其实单例模式维护的核心就是保证对应的实例对象是唯一的,那么就肯定会有人想方设法的去破环这种唯一性。这就是单例模式所存在的问题了。
破坏方式
解决方式
Singleton
类中添加 readResolve()
方法,在反序列化时被反射调用,如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新 new
出来的对象。null
的话,直接抛异常。Runtime
类就是使用的单例设计模式。
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
...
}
从上面源代码中可以看出 Runtime
类使用的是饿汉式(静态属性)方式来实现单例模式的。
编写不易,如果你感觉对你有帮助的话,请你三连支持,后面的文章会一点点更新。
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!