? 不断学习才是王道
? 继续踏上学习之路,学之分享笔记
? 总有一天我也能像各位大佬一样
?分享学习心得,欢迎指正,大家一起学习成长!
原创作品,更多关注我CSDN: 一个有梦有戏的人
准备将博客园、CSDN一起记录分享自己的学习心得!!!
单例模式,是java设计模式中最简单的设计模式,是属于创建类型模式。单例模式就是只能有一个实例,即一个类有且仅有一个实例,并且自行实例化向整个系统提供。
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。 -- (美)钟冠贤.Objective-C编程之道 iOS设计模式解析.北京市:人民邮电出版社,2011
UML图:

以下使用多线程测试的代码(如以下例子):
class Threads extends Thread {
@Override
public void run() {
StaticVariableStarve instance = StaticVariableStarve.getInstance();
System.out.println("StaticVariableStarve hashCode: " + instance.hashCode());
}
}
在main方法中调用start。
for (int i = 0; i < 5; i++) {
new Threads().start();
}
饿汉静态变量通过创建静态变量去实例化对象,在通过静态方法返回实例,其中需要实现私有化构造方法,使得外部不能通过new直接实例化对象。
代码如下:
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description: 单例模式 - 饿汉静态变量
* @Date: 2022-08-24
*/
public class StaticVariableStarve {
// 私有化构造方法
private StaticVariableStarve() {
}
// 创建静态变量实例化
private final static StaticVariableStarve singleton = new StaticVariableStarve();
// 返回对象
public static StaticVariableStarve getInstance() {
return singleton;
}
}
饿汉静态变量的测试
单例模式创建只能有一个实例,不管是用几个变量,最后他们都是同一个实例,如下测试,通过“==”判断对象实例是否一致,打印其hashcode可以发现是一样的。
// 饿汉静态变量
StaticVariableStarve singleton1 = StaticVariableStarve.getInstance();
StaticVariableStarve singleton2 = StaticVariableStarve.getInstance();
System.out.println("两者是否相同?" + (singleton1 == singleton2));
System.out.println("singleton1的hashcode:" + (singleton1.hashCode()));
System.out.println("singleton2的hashcode:" + (singleton2.hashCode()));
运行结果:

多线程:

这样写在类装载的时候就已经实例化了,避免了线程安全问题。但是,一开始就已经实例化了,没有使用lazy loading,就会导致有时候这个实例不需要使用,但是他仍然实例化了,这样就造成了内存浪费。
静态代码块中实例化对象,通过类主动去实例化对象,当调用到这个类的时候,静态代码块的代码就会运行,从而实例化对象。
代码如下:
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description: 饿汉静态代码块
* @Date: 2022-08-24
*/
public class StaticBlockStarve {
// 私有化构造方法
private StaticBlockStarve() {
}
// 构建静态变量
private static StaticBlockStarve singleton;
static {
singleton = new StaticBlockStarve();
}
// 返回对象
public static StaticBlockStarve getInstance() {
return singleton;
}
}
饿汉静态代码块测试
// 饿汉静态代码块
StaticBlockStarve singleton3 = StaticBlockStarve.getInstance();
StaticBlockStarve singleton4 = StaticBlockStarve.getInstance();
System.out.println("两者是否相同?" + (singleton3 == singleton4));
System.out.println("singleton1的hashcode:" + (singleton3.hashCode()));
System.out.println("singleton2的hashcode:" + (singleton4.hashCode()));
运行结果:

多线程:

通过 Lazy 初始化,但是线程不安全,这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
代码如下:
通过getInstance()获取实例,在方法内进行判断是否为空,不为空直接返回对象实例。
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description: 懒汉式-线程不安全
* @Date: 2022-08-24
*/
public class NotSafeThreadLazy {
// 私有变两个
private static NotSafeThreadLazy singleton;
// 私有构造
private NotSafeThreadLazy() {
}
// 通过方法实例化
public static NotSafeThreadLazy getInstance() {
if (singleton == null) {
singleton = new NotSafeThreadLazy();
}
return singleton;
}
}
测试
// 懒汉线程不安全
NotSafeThreadLazy singleton1 = NotSafeThreadLazy.getInstance();
NotSafeThreadLazy singleton2 = NotSafeThreadLazy.getInstance();
System.out.println("两者是否相同?" + (singleton1 == singleton2));
System.out.println("singleton1的hashcode:" + (singleton1.hashCode()));
System.out.println("singleton2的hashcode:" + (singleton2.hashCode()));
运行结果

多线程:可见生成了多个实例

用到了lazy loading,但只能在单线程下使用。但是在多线程中,可能会导致一个线程已经到达了if判空,但是还没有进行实例化,第二个线程就已经进入判空,并且也进入实例化。这样就会破坏了单例模式,两个实例化就不是同一个,因此这种方式是线程不安全,不推荐使用。
这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
代码如下:
通过lazy loading实例化对象,只在第一次运行实例化,在getInstance方法中使用synchronized保证线程安全。
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description: 懒汉式-线程安全
* @Date: 2022-08-24
*/
public class SafeThreadLazy {
// 私有变两个
private static SafeThreadLazy singleton;
// 私有构造
private SafeThreadLazy() {
}
// 通过方法实例化
public static synchronized SafeThreadLazy getInstance() {
if (singleton == null) {
singleton = new SafeThreadLazy();
}
return singleton;
}
}
多线程 :

采用双锁机制,安全且在多线程情况下能保持高性能。
在变量加上关键字volatile,在实例化的时候用synchronized线程锁,可以使线程安全。
volatile:是Java虚拟机提供的轻量级的同步机制,当某线程更新变量后,其他线程也能感知到。
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description: 双检锁/双重校验锁
* @Date: 2022-08-24
*/
public class DoubleCheckedLocking {
// 私有变两个
private static volatile DoubleCheckedLocking singleton;
// 私有构造
private DoubleCheckedLocking() {
}
// 通过方法实例化
public static DoubleCheckedLocking getInstance() {
if (singleton == null) { // [1]
synchronized (DoubleCheckedLocking.class) { // [2]
if (singleton == null) {
singleton = new DoubleCheckedLocking();
}
}
}
return singleton;
}
}
在getInstance()方法中,哪怕是多线程,都能保证线程安全以及单例模式。假如有多个线程,一个线程先到达了[1]判空成功后进入实例化,此时synchronized线程锁就会上锁,在还没实例化后,然而其他线程也过来了,他们也通过了[1]判空,但是在[2]处会被拦住,直到前一个实例化结束后才解锁,等到解锁后,也就已经实例化完成,singleton就已经不再是null。
多线程:

这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
代码如下:
通过SingletonHolder这个静态内部类实例化,采用类装载的方式进行实例化,但是一开始是不会实例化的,只有显式调用了getInstance(),使得SingletonHolder类被主动调用,从而实例化对象。
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description: 静态内部类
* @Date: 2022-08-24
*/
public class StaticInnerClass {
private StaticInnerClass() {}
// 静态内部类
public static class SingletonHolder {
private static final StaticInnerClass SINGLETON = new StaticInnerClass();
}
// 调用方法
public static StaticInnerClass getInstance() {
return SingletonHolder.SINGLETON;
}
}
采用了类装载的方式使实例化只有一个线程。在一开始StaticInnerClass被装载的时候,对象不一定被实例化。需要调用了getInstace()的方法,才会使得SingletonHolder被主动使用,装载SingletonHolder类,也就接着进行实例化对象。
多线程:

这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
代码如下:
package com.lyd.demo.singleton;
/**
* @Author: lyd
* @Description:
* @Date: 2022-08-24
*/
public enum Enumeration {
INSTANCE;
public void instanceMethod() {
System.out.println("实例的方法");
}
}
测试
// 枚举
Enumeration instance = Enumeration.INSTANCE;
Enumeration instance2 = Enumeration.INSTANCE;
System.out.println("两者是否相同?" + (instance == instance2));
System.out.println("instance的hashcode:" + (instance.hashCode()));
System.out.println("instance2的hashcode:" + (instance2.hashCode()));
instance.instanceMethod();
结果

多线程测试:

可发现多线程下枚举也是能够实现单例模式。
?创作不易,如有错误请指正,感谢观看!记得一键三连哦!?
?德德小建议:
理解设计模式不是一件简单的事情,需要不断的学习和动手去练习,才能理解。只有掌握好设计模式,才能够真正的理解SpringAOP和Mybatis的底层原理。各位读者可以和我一样,动手敲一敲代码,甚至用不同的例子来做,通过debug一步一步调试,还有就是多看看别人的例子。能够有助于理解!谢谢各位观看指点!❤️ ❤️ ❤️
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/