共计 3127 个字符,预计需要花费 8 分钟才能阅读完成。
download:高级前端进阶必修:自主打造高扩大的业务组件库含有笔记分享
独身模式只会更懒。
序
说到设计模式,十有八九,singleton 模式在面试中排名第一,这肯定是大多数人从入门到面试都无奈回避的基础知识。
然而,singleton 模式中并不只有懈怠模式和饥饿模式,大多数都是最根本的模式。如果你读过 spring 之类的出名框架源代码,你会发现他们的 singleton 模式编写和你所晓得的齐全不一样。
本文将为您带来 singleton pattern 的根本 -> 最优 -> 附加举荐法,帮忙您在面试中取得疯狂分。
又懒又饿
1. 饥饿的中国模式
饿模式简略的了解就是提前创建对象。
长处: 编写简略,没有线程同步的问题。
毛病: 因为对象要提前创立,所以不论用不必,总是占用内存。
倡议: 如果对象小而简略,应用饿中文模式。
公共最终类 Singleton {
// 创立良好的实例
公有动态 Singleton 实例 = new Singleton();
// 构造函数
公有 Singleton() {}
// 获取实例
公共动态 Singleton getInstance() {
返回实例;
}
}
复制代码
2. 懈怠模式
对懈怠模式的简略了解就是在须要的时候创建对象。
长处: 懒加载模式性能更高。
毛病: 思考多线程的同步。
举荐: 只有不合乎下面举荐的饿人条件,就用懒人模式。
公共最终类 Singleton {
公有动态单例实例 = null
// 构造函数
公有 Singleton() {}
// 获取实例
公共动态 Singleton getInstance() {
// 仅在对象为空时实例化该对象
if (null == instance) {
instance = new Singleton();
}
返回实例;
}
}
复制代码
同步锁
懒人的毛病就是多线程同步的问题,你能够马上想到用同步锁来解决这个问题。
这里应用 synchronized 关键字,通过代码块升高锁的粒度,最大水平的保障了性能开销。其实从 java8 开始,synchronized 的性能曾经有了很大的晋升。
公共最终类 Singleton {
公有动态单例实例 = null
// 构造函数
公有 Singleton() {}
// 获取实例
公共动态 Singleton getInstance() {
// 获取对象时增加同步锁
if (null == instance) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
返回实例;
}
}
复制代码
双重查看锁
尽管下面用了同步锁代码块,勉强解决了线程同步的问题,最大水平优化了性能开销,但实际上多线程环境下还是存在线程平安问题的。
当依然有多个线程进入 if 判断时,这个线程平安问题依然存在。尽管这种状况不肯定会产生,但极其状况下产生的概率很大。
这时候你就须要用到 DCL 了,就是你在面试中喜爱问的对于设计模式的双检锁模式。听起来很高大上,其实又多了一层判断。
说白了就是进入同步锁前后都查看,大大减少了线程平安的问题。
公共最终类 Singleton {
公有动态单例实例 = null
// 构造函数
公有 Singleton() {}
// 获取实例
公共动态 Singleton getInstance() {
// 第一个判断,当 instance 为 null 时,实例化对象。
if(null == instance) {
synchronized (Singleton.class) {
// 第二次判断,放入同步锁,实例为空时实例化对象
if(null == instance) {
instance = new Singleton();
}
}
}
返回实例;
}
}
复制代码
最佳双重查看锁
双检锁模式是单懒模式解决多线程下平安问题的最佳计划之一,但仍不是最好的写法。
这里是指令重排的概念,它在 java 内存模型中。我用最简略的形式帮你了解。
在 Java 中,一个对象在内存中执行指令的失常程序是: 调配 -> 创立 -> 援用,而在多线程环境中,因为语句的优化,JVM 可能会重新排列程序: 调配 -> 援用 -> 创立。
如果呈现这种状况,下面的双重查看锁定办法依然不能解决线程平安问题。
解决办法很简略,只需增加一个 volatile 关键字。
volatile 关键字的作用: 保障可见性和有序性。
公共最终类 Singleton {
// 增加 volatile 关键字
private volatile static Singleton 实例 = null
// 构造函数
公有 Singleton() {}
// 获取实例
公共动态 Singleton getInstance() {
// 第一个判断,当 instance 为 null 时,实例化对象。
if(null == instance) {
synchronized (Singleton.class) {
// 第二次判断,放入同步锁,实例为空时实例化对象
if(null == instance) {
instance = new Singleton();
}
}
}
返回实例;
}
}
复制代码
枚举模式
《无效的 Java》是 Java 行业十分受欢迎的一本书。对于想要深刻 Java 畛域的程序员来说,没有理由不读这本书。置信很多 Java 程序员不论有没有看过这本书,都听过。
然而,本书的作者举荐了一种繁多案例设计模式,即枚举。
原理很简略。在 Java 中,枚举类的域在编译后会被申明为 static 属性,JVM 会保障 static 润饰的成员变量只被实例化一次。
公共类 Singleton {
// 构造函数
公有 Singleton() {
}
// 从枚举中获取实例
公共动态 Singleton getInstance() {
返回 SingletonEnum。singleton . getinstance();
}
// 定义枚举
公有枚举 SingletonEnum {
独生子女;
公有单例实例;
// JVM 保障这个办法只被调用一次
SingletonEnum() {
instance = new Singleton();
}
公共 Singleton getInstance() {
返回实例;
}
}
}
复制代码
摘要
最初这里略微提一下,省得有人感觉设计模式有点累赘。
实际上,单例模式非常简单。饿汉模式和懒汉模式在很多开源框架中都有广泛应用,甚至饿汉模式用的更多。比方 Java 运行时类就是这么做的,简略粗犷。有趣味的能够本人看看源代码。
这些框架的作者难道没有意识到本文所形容的问题吗?不,不是的。用哪种形式写 singleton 模式往往要视状况而定,有些实践上会产生的问题在实践中往往能够疏忽。这个时候,他们更喜爱用最简略间接的写法。
真正的难点其实是面试。很多对于 singleton 模式的问题都喜爱问它的编写办法,存在的问题以及最佳计划。说白了就是造核弹,工厂里拧螺丝的面试。目标是理解你对设计模式的了解,从而判断你学习这门学科的态度和造诣。
所以,看完这篇文章,能够试着手动写,理解一下就够了。没必要深究太多,因为 Java 畛域须要破费精力的中央真的太多了。
感觉
最初说一下我的经验。所谓的设计模式当然能够给 Java 代码自身带来更多的优雅,然而我写了多年的 Java 代码,广泛感觉 Java 自身的装璜太多了,优雅往往带来代码自身的累赘。
在我加入过的 R &D 团队中,简直都能看到很多工程师写的优雅的代码,有些设计模式也写得很好,但显著的问题是可读性越来越差,这要求每个成员对 Java 都有很高的造诣,甚至在某些状况下会给人力资源带来压力,从实用的角度来看是不适合的。
我更多的倡议是: 在面试或学习中对设计模式有很好的理解是无益的,但在实践中,尽量应用不太简单的设计模式,优先思考简洁间接的代码,这样有利于整个团队的前期保护,甚至能够放慢人员变动后新成员对我的项目的适应。因为工作还是以业绩为导向,简略高效就能够了,能够得心应手的玩本人的集体我的项目。
文章参考 java 自学 https://www.zxit666.com