深圳高端网站开发,东莞公司官网推广,淘宝网网页设计作业,网站增加新闻功能文章目录 1、模式定义2、代码实现#xff08;1#xff09;双重判空加锁方式两次判空的作用#xff1f;volatile 关键字的作用#xff1f;构造函数私有#xff1f; #xff08;2#xff09;静态内部类【推荐】#xff08;3#xff09;Kotlin中的单例模式lateinit 和 by… 文章目录 1、模式定义2、代码实现1双重判空加锁方式两次判空的作用volatile 关键字的作用构造函数私有 2静态内部类【推荐】3Kotlin中的单例模式lateinit 和 by lazy 的区别 3、优缺点4、参考资料 1、模式定义
作为对象的创建模式单例模式确保某一个类只有一个实例而且自行实例化并向整个系统提供这个实例。这个类称为单例类。单例特别1单例模式只能有一个实例。2单例类必须创建自己的唯一实例。3单例类必须向其他对象提供这一实例。
2、代码实现
1双重判空加锁方式
public class Singlnton{private static volatile Singlnton instance;private Singlnton(){}public static Singlnton getInstance(){ // 1if(instancenull){ // 2synchronized(Singlnton.class){ // 3if(instancenull){ // 4instance new Singlnton(); // 5}}}return instance;}}
两次判空的作用
第一次避免加锁第二次进行实例化
volatile 关键字的作用
双重检锁单例模式在 CPU 的工作流主要分为三步1分配内存对象空间。2初始化对象。3设置 instance 执行刚才分配的内存地址。注意 JVM 和 CPU 优化会指令重排上面顺序会变成 1 - 3 - 2单线程环境下此顺序是没有问题2 和 3 前后没有依赖性但是在多线程情况下会有这种情况当线程 A 在执行第 5 行代码时B 线程进来执行到第 2 行代码。假设此时 A 执行的过程中发生了指令重排序即先执行了 1 和 3没有执行 2。那么由于 A 线程执行了 3 导致 instance 指向了一段地址所以 B 线程判断 instance 不为 null会直接跳到第 6 行并返回一个未初始化的对象此时会产生空指针异常。volatile 能保持指令的有序性能够有效禁止指令重排序。注意“Singlnton instance” 相当于分配内存对象空间“new Singlnton()” 相当于初始化对象相当于设置 instance 执行刚才分配的内存地址。
构造函数私有
无法通过调用该类的构造函数来实例化该类的对象只有通过该类提供的静态方法 getInstance 来得到该类的唯一实例
2静态内部类【推荐】
public class Singlnton{private Singlnton(){}private static class SinglntonHolder{private static Singlnton INSTANCE new Singlnton();}public static Singlnton getInstance(){return SinglntonHolder.INSTANCE;}}
利用 JAVA 虚拟机加载类的特性实现延迟加载和线程安全由于静态单例对象没有作为 Singleton 的成员变量直接实例化因此类加载时不会实例化 Singleton第一次调用 getInstance() 时将加载内部类 SingletonHolder在该内部类中定义了一个 static 类型的变量 INSTANCE此时会首先初始化这个成员变量由 Java 虚拟机来保证其线程安全性确保该成员变量只能初始化一次。由于 getInstance() 方法没有任何线程锁定因此其性能不会造成任何影响。类加载机制
3Kotlin中的单例模式
class Singlnton private constructor(){companion object{val instance : Singlnton by lazy(mode LazyThreadSafetyMode.SYNCHRONIZED) {Singlnton() }}}class Singlnton private constructor(){companion object{Volatileprivate var instance: Singlnton? nullfun getInstance(): Singlnton instance ?: synchronized(this) {instance ?: Singlnton().also {instance it}}}}lateinit 和 by lazy 的区别
lateinit 只能用于修饰变量 var不能用于可空的属性和 Java 的基本类型。lateinit 可以在任何位置初始化并且可以初始化多次。lazy() 只能用于修饰常量 val并且 lazy() 是线程安全的。lazy() 是一个函数可以接受一个 Lambda 表达式作为参数第一次调用时会执行 Lambda 表达式以后调用该属性会返回之前的结果。lazy() 源码分析
3、优缺点
优点 1在内存里只有一个实例减少了内存的开销尤其是频繁的创建和销毁实例。2避免对资源的多重占用。 缺点 1没有接口不能继承与单一职责原则冲突一个类应该只关心内部逻辑而不关心外面怎么样来实例化。2滥用单例会带来一些负面问题。如果实例化的对象长时间不被使用系统会认定为垃圾而回收这将导致共享对象状态的改变 注意事项不能使用反射调用私有构造器这样会实例化一个新的对象如何避免反射创建新的单例对象
4、参考资料
单例模式 Android 校招面试指南只能在手机端打开