第一种(懒汉,线程不安全):
-
public
class
Singleton {
-
private
static
Singleton instance;
-
-
public
static
Singleton getInstance() {
-
if
(instance ==
null
) {
-
instance = new
Singleton();
-
}
-
return
instance;
-
}
-
}
这种写法lazy loading很明显,但是致命的是在多线程不能正常工作。
第二种(懒汉,线程安全):
-
public
class
Singleton {
-
private
static
Singleton instance;
-
-
public
static
synchronized
Singleton getInstance() {
-
if
(instance ==
null
) {
-
instance = new
Singleton();
-
}
-
return
instance;
-
}
-
}
这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。
第三种(饿汉):
-
public
class
Singleton {
-
private
static
Singleton instance =
new
Singleton();
-
-
public
static
Singleton getInstance() {
-
return
instance;
-
}
-
}
这种方式基于
classloder
机制避免了多线程的同步问题,不过,
instance
在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用
getInstance
方法,
但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化
instance
显然没有达到
lazy loading
的效果。
第四种(饿
汉,变种):
-
public
class
Singleton {
-
private
Singleton instance =
null
;
-
static
{
-
instance = new
Singleton();
-
}
-
-
public
static
Singleton getInstance() {
-
return
this
.instance;
-
}
-
}
表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。
第五种(静态内部类):
-
public
class
Singleton {
-
private
static
class
SingletonHolder {
-
private
static
final
Singleton INSTANCE =
new
Singleton();
-
}
-
-
public
static
final
Singleton getInstance() {
-
return
SingletonHolder.INSTANCE;
-
}
-
}
这种方式同样利用了
classloder
的机制来保证初始化
instance
时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要
Singleton
类被装载了,那么
instance
就会被实例化(没有达到
lazy loading
效果),而这种方式是
Singleton
类被装载了,
instance
不一定被初始化。因为
SingletonHolder
类没有被主动使用,只有显示通过调用
getInstance
方法时,才会显示装载
SingletonHolder
类,从而实例化
instance
。想象一下,如果实例化
instance
很消耗资源,我想让他延迟加载,另外一方面,我不希望在
Singleton
类加载时就实例化,因为我不能确保
Singleton
类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化
instance
显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。
第六种(枚举):
-
public
enum
Singleton {
-
INSTANCE;
-
public
void
whateverMethod() {
-
}
-
}
这种方式是Effective Java作者Josh Bloch
提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特
性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。
第七种(双重校验锁):
-
public
class
Singleton {
-
private
volatile
static
Singleton singleton;
-
-
public
static
Singleton getSingleton() {
-
if
(singleton ==
null
) {
-
synchronized
(Singleton.
class
) {
-
if
(singleton ==
null
) {
-
singleton = new
Singleton();
-
}
-
}
-
}
-
return
singleton;
-
}
-
}
这个是第二种方式的升级版,俗称双重检查锁定,详细介绍请查看:http://www.ibm.com/developerworks/cn/java/j-dcl.html
在JDK1.5之后,双重检查锁定才能够正常达到单例效果。
总结
有两个问题需要注意:
1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet
容器对每个servlet
使用完全不同的类装载器,这样的话如果有两个servlet
访问一个单例类,它们就都会有各自的实例。
2.如果Singleton
实现了java.io.Serializable
接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。
对第一个问题修复的办法是:
-
private
static
Class getClass(String classname)
-
throws
ClassNotFoundException {
-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-
-
if
(classLoader ==
null
)
-
classLoader = Singleton.class
.getClassLoader();
-
-
return
(classLoader.loadClass(classname));
-
}
-
}
对第二个问题修复的办法是:
-
public
class
Singleton
implements
java.io.Serializable {
-
public
static
Singleton INSTANCE =
new
Singleton();
-
-
protected
Singleton() {
-
-
}
-
private
Object readResolve() {
-
return
INSTANCE;
-
}
-
}
对我来说,我比较喜欢第三种和第五种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下,我会使用第三种方
式,只有在要明确实现lazy
loading效果时才会使用第五种方式,另外,如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例,不过,我一直会保证我的程序是线程安全
的,而且我永远不会使用第一种和第二种方式,如果有其他特殊的需求,我可能会使用第七种方式,毕竟,JDK1.5已经没有双重检查锁定的问题了。
========================================================================
superheizai
同学总结的很到位:
不过一般来说,第一种不算单例,第四种和第三种就是一种,如果算的话,第五种也可以分开写了。所以说,一般单例都是五种写法。懒汉,恶汉,双重校验锁,枚举和静态内部类。
我很高兴有这样的读者,一起共勉。
鉴于很多人说我没有写私有构造方法,我这里声明一下,不是我忘了写,是我故意嫌麻烦省略掉了,我以为大家都懂得

分享到:
相关推荐
该代码使用scikit-learn的乳腺癌数据集,完成分类模型训练与评估全流程。主要功能包括:数据标准化、三类模型(逻辑回归、随机森林、SVM)的训练、模型性能评估(分类报告、混淆矩阵、ROC曲线)、随机森林特征重要性分析及学习曲线可视化。通过`train_test_split`划分数据集,`StandardScaler`标准化特征,循环遍历模型进行统一训练和评估。关键实现细节包含:利用`classification_report`输出精确度/召回率等指标,绘制混淆矩阵和ROC曲线量化模型效果,随机森林的特征重要性通过柱状图展示,学习曲线分析模型随训练样本变化的拟合趋势。最终将原始数据和预测结果保存为CSV文件,便于后续分析,并通过matplotlib进行多维度可视化比较。代码结构清晰,实现了数据处理、模型训练、评估与可视化的整合,适用于乳腺癌分类任务的多模型对比分析。
内容概要:本文作为PyTorch的入门指南,首先介绍了PyTorch相较于TensorFlow的优势——动态计算图、自动微分和丰富API。接着讲解了环境搭建、PyTorch核心组件如张量(Tensor)、autograd模块以及神经网络的定义方式(如nn.Module),并且给出了详细的神经网络训练流程,包括前向传播、计算损失值、进行反向传播以计算梯度,最终调整权重参数。此外还简要提及了一些拓展资源以便进一步探索这个深度学习工具。 适用人群:初次接触深度学习技术的新学者和技术爱好者,有一定程序基础并希望通过PyTorch深入理解机器学习算法实现的人。 使用场景及目标:该文档有助于建立使用者对于深度学习及其具体实践有更加直观的理解,在完成本教程之后,读者应当能够在个人设备上正确部署Python环境,并依据指示独立创建自己的简易深度学习项目。 其他说明:文中所提及的所有示例均可被完整重现,同时官方提供的资料链接也可以方便有兴趣的人士对感兴趣之处继续挖掘,这不仅加深了对PyTorch本身的熟悉程度,也为未来的研究或者工程项目打下了良好的理论基础和实践经验。
此高校心理教育辅导系统功能分析主要分为管理员功能模块、教师功能模块和学生功能模块三大模块,下面详细介绍这三大模块的主要功能: (1)管理员:管理员登陆后可对系统进行全面管理,管理员主要功能模块包括个人中心、学生管理、教师管理、辅导预约管理、学生信息管理、测评结果分析管理、心理健康学习管理、试题管理、留言板管理、试卷管理、系统管理以及考试管理,管理员实现了对系统信息的查看、添加、修改和删除的功能。管理员用例图如图3-1所示。(2)学生:学生进入本高校心理教育辅导系统前台可查看系统信息,包括首页、心理健康信息、试卷列表、公告通知以及留言反馈等,注册登录后主要功能模块包括个人中心、辅导预约管理以及考试管理。(3)教师:教师学生登录后主要实现的功能模块包括个人中心、辅导预约管理、学生信息管理、测试结果分析管理、心理健康学习管理、试卷管理、试题管理、留言板管理、考试管理。Spring Boot是一个简化程序设置的拥有开箱即用的框架,它主要的优点是根据程序员不同的设置而生成不同的代码配置文件,这样开发人员就不用每个项目都配置相同的文件,从而减低了开发人员对于传统配置文件的时间,提高了开发效率。它内
网络文化互动中的虚拟现实技术应用
自驾游中如何预防迷路情况
实现多人聊天的客户端小程序
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
漫画中的文化元素挖掘
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
,,Qt源程序~界面设计例程(XML文件读取+滚动区域放置控件+保存多sheetExcel文件) IDE版本: Qt creator 4.8.0 Qt 5.12.0 代码特点: 1.能读取xml格式文件,并通过其配置界面; 2.能在滚动区域内放置多种控件,界面大小不够会出现滚动条来扩展界面; 3.能通过xml配置文件初始化联动的单选框,输入框和表格; 4.通过程序动态新建单选框,输入框和表格; 5.将表格保存为Excel文件,每个表格就是一个sheet。 视频不够清晰,请上B站看: 【Qt例程:界面设计项目(XML文件读取+滚动区域放置控件+保存Excel文件)- ,Qt源程序; XML文件读取; 滚动区域放置控件; 保存多sheet Excel文件; Qt Creator 4.8.0; Qt 5.12.0; 动态创建控件; 界面设计例程。,Qt程序进阶:XML文件读取与处理,滚动区域控件布局,多sheet Excel文件保存功能
,,FPGA 以太网 UPD IP 协议实现 fpga 千兆以FPGA 以太网 UPD IP 协议实现 fpga 千兆以FPGA 以太网 UPD IP 协议实现, fpga 千兆以太网接口控制器,FPGA UDP IP协议实现 在FPGA上实现UDP通信,Verilog HDL描述语言实现,数据链路层,网络层,传输层有纯逻辑实现。 接口为GMII接口,与外部phy对接。 实验器件为s6,因此编译环境用的是ISE14.7。 vivado轻松无压力,随意移植。 ,FPGA; 以太网; UPD; IP协议; 千兆以太网接口控制器; Verilog HDL描述语言; 数据链路层; 网络层; 传输层; 接口为GMII接口; 编译环境为ISE14.7。,基于FPGA的千兆以太网UDP IP协议实现与优化
eclipse-inst-jre-win64.rar
内容概要:本文档详细介绍了一个基于Transformer和BiLSTM双向长短期记忆神经网络结合贝叶斯优化(BO)进行时间序列预测的项目。该项目主要解决传统方法在处理复杂非线性关系、多变量依赖和大规模数据时存在的局限性,提升预测精度和计算效率。项目通过MATLAB实现完整的程序、GUI设计和详细的代码说明,涵盖数据预处理、模型设计与训练、超参数调优、评估与应用等各个环节。同时探讨了项目的挑战和未来改进方向,为深度学习技术在时间序列预测中的应用提供了实用价值。 适合人群:对时间序列预测感兴趣的研究人员和技术人员,尤其是具有一定深度学习基础并且希望深入了解和实践Transformer、BiLSTM及相关优化技术的专业人士。 使用场景及目标:①为金融、能源、气象等多个领域的实际问题提供时间序列预测解决方案,包括股市预测、电力负载预估等;②提高预测模型的泛化能力和准确性;③优化模型的超参数选取,从而提高训练速度和效率。 其他说明:文中特别强调了数据处理的重要性,如去除噪声、特征选择等问题,并介绍了贝叶斯优化技术的应用,使得模型能够在较少尝试下找到最优配置。同时展示了如何通过图形化界面展示训练过程和评估结果,确保用户体验友好。此外,文档还包括了防止过拟合、提高模型性能的各种技巧,如正则化、早期停止、Dropout等措施。总体而言,本项目致力于提供一套完善的深度学习解决方案,促进跨学科应用和发展。
励志图书中的时间管理、目标设定与自我提升
当前资源包含初中高级闯关习题
亲子自驾游趣味活动推荐
内容概要:本文介绍了BERT(Bidirectional Encoder Representations from Transformers),它是一种新型的语言表示模型,通过利用掩码语言模型(MLM)和下一句预测任务(NSP),实现了从无标注文本中预训练深层双向表示模型的方法。这种双向注意力机制允许模型在同一层联合调节左右语境,极大地提升了下游自然语言处理任务的性能。与单向语言模型如ELMo、GPT不同,BERT能直接捕捉句子内部复杂的依存关系,在多项NLP基准测试中刷新了记录,显著优于以前的最佳表现。 适合人群:从事自然语言处理研究的技术人员以及对该领域有兴趣的研究学者和开发者。 使用场景及目标:适用于需要高级别自然语言理解和推理能力的任务,特别是涉及问答系统、机器翻译和情感分析等任务的研发团队和技术部门。通过采用BERT可以快速提高相关应用场景中的精度。 其他说明:BERT不仅展示了双向建模相对于传统单向方法的优势,还强调了充分预训练对于改善小型数据集上模型表现的关键作用。此外,文中还详细比较了与其他几种现有先进模型的特点,并提供了具体的实验设置和技术细节供进一步探究。
漫画作品与网络文化互动
# 基于SpringBoot的“体育购物商城”的设计与实现(源码+数据库+文档+PPT) - 开发语言:Java - 数据库:MySQL - 技术:SpringBoot - 工具:IDEA/Ecilpse、Navicat、Maven (1)系统管理员主要对个人中心、用户管理、商品分类管理、体育用品管理、系统管理、订单管理等功能进行管理。 (2)用户进入系统可以对首页、体育用品、活动公告、在线客服、购物车、个人中心等功能进行操作。
,,三菱fx5u plc CCD检测fb程序 此程序已经实际设备上批量应用,机器人配合CCD视觉检测,每个工位循环拿照。 用的FB写法,程序成熟可靠,借鉴价值高,程序注释详细,用的三菱fx5u系列plc。 是新手入门级三菱fx5u电气爱好从业人员借鉴和参考经典案列。 ,核心关键词:三菱fx5u PLC; CCD检测; FB程序; 机器人配合; 视觉检测; 循环拍照; 程序成熟可靠; 注释详细; 新手入门级参考案列。,三菱FX5U PLC CCD视觉检测FB程序:成熟可靠,循环拍照应用案例