题外话

上一次被人说文章名字取得不霸气,于是这一次我采用了这么霸气的名字,但实际上我是一个很低调的人。设计模式刚入门的小伙伴可以先看看这篇《设计模式入门》,在文章末尾也将列出“设计模式系列”文章。欢迎大家关注留言投币丢香蕉。

什么是单例模式

  1. 单例模式是设计模式中最简单的形式之一。
  2. 一个类有且仅有一个对象实例,并自行实例化向整个系统提供。

为何要学习单例模式

  1. 有些对象我们只需要一个。例如:线程池,缓存,对话框等等,创建太多此类实例可能会导致程序行为异常、资源使用过量等问题。
  2. 防止造成资源浪费。静态变量也可以给整个系统提供一个实例,但此对象在程序一开始就被创建好了,万一在某次运行中没有使用到此对象,资源就被浪费了。
  3. 没有富萝莉包养我

走进单例模式

单例模式有三个要点,分别是:

  1. 仅有一个实例。
  2. 自动实例化。
  3. 向整个系统提供。

这也就是我们在写单例模式时候必须要遵守的几点。根据上面的条件,我们能够得出:

  1. 构造方法必须私有化,禁止外部随意new Singleton();
  2. 类内部实例化一个实例对象。
  3. 对外提供一个可以获取内部唯一实例对象的方法。

懒汉式

懒汉式这名字的精髓在于懒,在代码中,这种懒代表着需要的时候才创建实例,不需要就不创建了,这样保证了资源的不浪费。

Java懒汉式

public class JavaSingleton {private JavaSingleton(){}//私有构造方法private static JavaSingleton instance;//提供一个实例对象public static JavaSingleton getInstance(){//对外提供可获取唯一实例化对象的方法if(instance == null)instance = new JavaSingleton(); //延迟实例化return instance;}
}
复制代码

Kotlin懒汉式1

class KotlinSingleton private constructor() {private var instance : KotlinSingleton? = nullfun getInstance(): KotlinSingleton? {if(instance == null)instance = KotlinSingleton()return instance}
}
复制代码

Kotlin懒汉式2

class KotlinSingleton private constructor() {companion object {val instance by lazy(LazyThreadSafetyMode.NONE) {KotlinSingleton()}}
}// 在Kotlin 中调用
KotlinSingleton.instance.xx()
// 在Java 中调用
KotlinSingleton.Companion.getInstance().xx()
复制代码

kotlin方式1就是直译了java方式,没啥说的。kotlin方式2写着很简洁,也很明了。要提一点的就是companion object,他类似public static,这一点从下面调用方式也看得出来。lazy属性表明是懒加载方式,LazyThreadSafetyMode.NONE表明了这种方式,线程不安全。

为啥不安全??!!

我们已经按照单例模式三个要点写出了单例模式,其实都已经讲完了。但为何还有其他一些写法呢? 因为我们是程序员啊!优化!优化!优化! 单线程进程下,懒汉式完全够用。但实际开发哪还有什么单线程程序。既然存在多线程,就存在并发性,如果两个线程同时进入非空判断,问题就出现了。线程一可能创建了一个instance,线程二因为已经非空判断为空了,所以也创建了个instance。这样程序肯定不会朝着你预想的方向去。所以我们可以给非空判断加一把锁,防止多线程同时进入非空判断。

同步锁

Java方式

public class JavaSingleton {private JavaSingleton(){}//私有构造方法private static JavaSingleton instance;//提供一个实例对象public static synchronized JavaSingleton getInstance(){//对外提供可获取唯一实例化对象的方法if(instance == null)instance = new JavaSingleton(); //延迟实例化return instance;}
}
复制代码

Kotlin方式

class KotlinSingleton private constructor() {private var instance : KotlinSingleton? = null@Synchronized //用注解就okk了。fun getInstance(): KotlinSingleton? {if(instance == null)instance = KotlinSingleton()return instance}
}
复制代码

简单!粗暴!太粗暴了!Synchronized 是一把重型锁,对性能影响相当的大,像单例这样在软件中可能多次获取,那性能将会大大地降低!所以,这种方式不建议使用。

饿汉式

为了解决多线程的问题,又不想降低性能,“饿汉式”就来了。饿汉式名字精髓在于“饿”,迫切的想吃东西,在代码中表示,迫切的想有一个单例对象!即在初始化的时候,就把单例创建好,之后要用就直接return,但是不用就浪费了。这也是饿汉式的缺点。

Java方式

public class JavaSingleton {private JavaSingleton(){}//私有构造方法private static JavaSingleton instance = new JavaSingleton();//提供一个实例对象public static JavaSingleton getInstance(){//对外提供可获取唯一实例化对象的方法return instance;}
}
复制代码

Kotlin方式

object KotlinSingleton {//null
}// 在Kotlin 中调用
KotlinSingleton.xx()
// 在Java 中调用
KotlinSingleton.INSTANCE.xx()复制代码

酥糊!Kotlin!有牌面!

双重检查锁

前面讲的三种方式都有不同程度的缺点。而双重检查锁,既保证了延迟加载不浪费资源,又保证了较好的性能。但双重检查锁不适用于1.4以及更早版本的java。

Java方式

public class JavaSingleton {private JavaSingleton(){}//volatile确保了当instance初始化为JavaSingleton实例时,多个线程正确的处理instance变量。private volatile static JavaSingleton instance;public static JavaSingleton getInstance(){if(instance == null){synchronized (JavaSingleton.class){//只有第一次才彻底执行锁块代码if(instance == null){instance = new JavaSingleton();}}}return instance;}
}
复制代码

Kotlin方式1

class KotlinSingleton private constructor() {@Volatile  //用注解就okk了private var instance : KotlinSingleton? = nullfun getInstance(): KotlinSingleton? {if(instance == null){synchronized(KotlinSingleton::class){if(instance == null){instance = KotlinSingleton()}}}return instance}
}
复制代码

Kotlin方式2

class KotlinSingleton private constructor() {companion object {val instance by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED){KotlinSingleton()}}
}// 在Kotlin 中调用
KotlinSingleton.instance.xx()
// 在Java 中调用
KotlinSingleton.Companion.getInstance().xx()
复制代码

“双重检查锁”的没有明显的缺点,如果非要说一个,可能就是太复杂了。kotlin还好,java里面写着相当的复杂。如果程序对性能没有考虑的话,这样写显然就太麻烦了。

关于LazyThreadSafetyMode
延迟属性 Lazy 可选LazyThreadSafetyMode三种模式:

  • SYNCHRONIZED —— 双重检查锁式,默认使用。
  • PUBLICATION —— 允许多个线程同时初始化实例,但只采用最先返回的实例。
  • NONE —— 没有任何的线程安全的保证和开销。

内部类式(店长推荐!!)

不要私信问我店长是谁! 总之这种方式,解决了延迟加载,线程安全的问题,还代码量少!简直美滋滋!但跟之前不同的是,没有声明实例对象。

Java方式

public class JavaSingleton {private JavaSingleton(){}private static class Holder{private static JavaSingleton instance = new JavaSingleton();}public static JavaSingleton getInstance(){return Holder.instance;}
}
复制代码

Kotlin方式

class KotlinSingleton private constructor() {companion object {fun getInstance() = Holder.instance}private object Holder{val instance = KotlinSingleton()}
}
复制代码

在类加载时,因为没有调用getInstance()所以Holder也不会加载,这样就实现了懒加载。调用getInstance()时,JVM会主动保证类加载的安全性,所以线程也是安全的。kotlin的写法就是java的翻译版本。

民间大神版本

上面几种方式都是比较官方的版本,下面介绍几个民间版本,是真大神还是抖机灵,自行判断。我也去研究研究!

来自知乎@丌冰: “我觉得这样就好了,什么懒加载,双重什么什么,什么什么的”

fun main(args: Array<String>) {Instance.INSTANCE.fun1()print(Instance.INSTANCE.fun2())
}
enum class Instance {INSTANCE;fun fun1(){}fun fun2():Any?{return null}
}作者:丌冰
链接:https://www.zhihu.com/question/52377186/answer/303561470
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复制代码

可见Android官方并不推荐使用枚举,占用内存较多。

来自刘望舒的设计模式(二)单例模式的七种写法:

public class SingletonManager { private static Map<String, Object> objMap = new HashMap<String,Object>();private Singleton() { }public static void registerService(String key, Objectinstance) {if (!objMap.containsKey(key) ) {objMap.put(key, instance) ;}}public static ObjectgetService(String key) {return objMap.get(key) ;}
}
复制代码

这也是比较少见的单例写法,将多个单例放在进SingletonManager 的静态map中统一管理。我是觉得有点太过于复杂,容易出错。

以上版本仅供参考,要是用了对程序造成了什么不好的影响,别找我。

关于单例的其他问题

关于继承: 不能继承!别想了。
关于单例: 尽量少使用单例。
关于我还没想到的问题: 欢迎加群讨论557247785。

总结

单例方式 优点 缺点
懒汉式 懒加载 线程不安全
同步锁 线程安全 多次获取的性能很低
饿汉式 简单、易写 可能引起资源浪费
双重检查锁 第一次获取才加锁 写法复杂
内部类式 简单、易写 暂无
民间大神式 欢迎留言跟我讨论 或者加qq群:557247785

以下是我“设计模式系列”文章,欢迎大家关注留言投币丢香蕉。

设计模式入门
Java与Kotlin的单例模式
Kotlin的装饰者模式与源码扩展
由浅到深了解工厂模式

Java与Kotlin的单例模式(霸气.jpg)相关推荐

  1. java小组口号,小组口号霸气

    恒心无愧组:你争我辩,争辩课堂精彩.你说我论,论说课堂真谛.以下是小编为大家整理的口号,希望大家能够喜欢! 1.飞翔小组:智勇双全,我心飞翔. 2.队名:巨人队,团队口号:兄弟加油. 3.队名:xx( ...

  2. 超有霸气的,有影响力的Java/C++/ASP.NET面试题

    1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二 ...

  3. 五年Java外包转型大数据架构,就是这么霸气

    五年Java外包转型大数据架构,就是这么霸气 前言 乔二爷(化名)是我学习群的元老,我们去年就认识,他是五年Java经验的老鸟.去年年底他刚开始学大数据的时候给我打过电话,咨询一些学习路线上的问题,那 ...

  4. java小组项目口号,小组口号霸气押韵大全(精选60句)

    小组口号霸气押韵大全(精选60句) 在平日的学习.工作和生活里,大家总少不了接触一些耳熟能详的口号吧,高效的口号具有针对性,时效性,鼓动性和简洁性的特点.那些被广泛运用的口号都是什么样子的呢?下面是小 ...

  5. java小组的队名,霸气小组名称口号大全

    [导语]快乐无限小组:脚踏实地,挑战自我:人人参与展现自我:齐心合力,快乐学习:取长补短,共同进步! 一:超越小组:奋发向上,享受成功! 二:*小组:让生活充满*,让学习丰富多彩 三:合作快车小组:年 ...

  6. 精彩回顾 | 华为 HDG 成都站霸气上演 蓉城风云再起

    文/陆海慧 一年好景君须记,最是橙黄橘绿时.秋天象征着成熟,意味着丰收.对于 HDG 的开发者们来说正是收获知识.结交知己的好时节. 9 月 24 日 "HDG 华为开发者汇"在天 ...

  7. 腾讯霸气回应年终奖传言:年终奖的4种故事,每年重复上演一遍

    黑客技术 点击右侧关注,了解黑客的世界! Java开发进阶 点击右侧关注,掌握进阶之路! Python开发 点击右侧关注,探讨技术话题! 作者 l 粥左罗主创团 来源 l 粥左罗(ID:fangdus ...

  8. Kotlin 静态内部类单例模式的正确实现方式

    本篇是对现网上流传的 Kotlin 实现静态内部类单例模式的纠正,为了把原理说清楚,文章前奏可能会有些长,熟悉静态内部类单例模式原理的朋友,可以直接跳转到文章最后,直接看结果即可. 最近在整理基础库的 ...

  9. 手把手教你学Kotlin (2):task1-6 函数,Java to Kotlin Convert,(持续更新中)

    文章目录 task1:函数 task2:Java to Kotlin Convert task3:Named arguments task1:函数 先看任务介绍: 这个任务的意思是修改代码,让函数返回 ...

最新文章

  1. Webx示例-PetStore分析1
  2. 用BP人工神经网络识别手写数字——《Python也可以》之三
  3. Android studio中不同颜色代表什么意思
  4. 英语语法最终珍藏版笔记-18what 从句的小结
  5. 鸿蒙系统有无隐私空间,华为鸿蒙OS系统有隐私空间功能吗 华为p40使用鸿蒙系统体验评测...
  6. EasyUI学习总结(二)——easyloader分析与使用
  7. java多态的简单例子_要JAVA的简单例子,继承\多态的,详细讲解运行的每一步
  8. 通过rss阅读器写blog
  9. 在Ubuntu 18.04上安装Nginx
  10. java web 基础框架搭建_JavaWeb之搭建自己的MVC框架(一)
  11. Mar9th 海尔java面试
  12. Linux僵尸进程详解
  13. ab网站压力测试命令的参数、输出结果的中文注解
  14. 斐波那契数列(II)
  15. Vue-html5-editor 编辑器的使用及一些问题解决
  16. 趋势判研:基于Web3.0的智能生态体——保险科技生态建设...
  17. linux安装过程进入终端,怎么安装国产Linux中标麒麟操作系统?安装全过程分享...
  18. Android 删除图片后刷新媒体库
  19. 达梦redo log损坏的处理办法
  20. 第2关:求五边形的面积

热门文章

  1. Java基础语法-while循环
  2. 为什么要进行天线对准?如何在无线链路部署中改善天线对准?
  3. 数据科学与大数据分析之项目5-情感分析
  4. 网站日记分析插件【土拨鼠网站日记管理(分析推送二合一)】宝塔插件,日记分析和网站收录推送
  5. 使用VMware Workstation 12 创建虚拟机的方法
  6. 进程 — 子进程与父进程的关系
  7. cvs add: added independently by second party 问题解决
  8. reg52.h中文详细注解
  9. 深度学习的最新进展及诺亚方舟实验室的研究
  10. 一键强制去掉PDF密码