深度认识单例模式;在Android源码中的应用(1)

单例模式的类图看起来很简单,一个私有的当前类型的成员变量,一个私有的构造方法,一个 getInstance 方法,**创建对象不再通过new 而通过 getInstance 让该类自行创建。**相信我们大多数人使用的单例模式都是这种,因为太简单了。但是单例模式的写法可不止这一种。接下来我们一起来看一下单例模式的九种写法。

单例模式的九种写法

一、饿汉式(静态常量)

/**

  • 饿汉式(静态常量)
    */
    class King {
    private static final King kingInstance = new King();

static King getInstance() {
return kingInstance;
}

private King() {
}
}

  • 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

  • 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

二、饿汉式(静态代码块)

/**

  • 饿汉式(静态代码块)
    */
    class King {
    private static King kingInstance;

static {
kingInstance = new King();
}

private King() {
}

public static King getKingInstance() {
return kingInstance;
}
}

  • 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

  • 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

三、懒汉式(线程不安全)

/**

  • 懒汉式(线程不安全)
    */
    public class King {
    private static King kingInstance;

private King() {
}

public static King getKingInstance() {
if (kingInstance == null) {
kingInstance = new King();
}
return kingInstance;
}
}

优点:懒加载,只有使用的时候才会加载。

缺点:但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

四、懒汉式(线程安全)

/**

  • 懒汉式(线程安全,同步方法)
    */
    public class King {
    private static King kingInstance;

private King() {
}

public static synchronized King getKingInstance() {
if (kingInstance == null) {
kingInstance = new King();
}
return kingInstance;
}
}

  • 优点:懒加载,只有使用的时候才会加载,获取单例方法加了同步锁,保障线程安全。

  • 缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。

五、懒汉式(线程安全,同步代码块)

/**

  • 懒汉式(线程安全,同步代码块)
    */
    public class King {
    private static King kingInstance;

private King() {
}

public static King getKingInstance() {
if (kingInstance == null) {
synchronized (King.class) {
kingInstance = new King();
}
}
return kingInstance;
}
}

  • 优点:改进了第四种效率低的问题。

  • 缺点:不能完全保证单例,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。

六、双重检查(DCL)

/**

  • 双重检查(DCL)
    */
    public class King {

private static volatile King kingInstance;

private King() {
}

public static King getKingInstance() {
if (kingInstance == null) {
synchronized (King.class) {
if (kingInstance == null){
kingInstance = new King();
}
}
}
return kingInstance;
}
}

  • 优点:线程安全;延迟加载;效率较高。

  • 缺点:JDK < 1.5 的时候不可用

  • 不可用原因:由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统运行效率降低,而JDK 1.5 以及之后的版本都修复了这个问题。(面试装逼用,谨记!!!)

七、静态内部类

/**

  • 静态内部类
    */
    public class King {

private King() {
}

private static class KingInstance{
private static final King KINGINSTANCE = new King();
}

public static King getInstance(){
return KingInstance.KINGINSTANCE;
}
}

  • 优点:避免了线程不安全,延迟加载,效率高。

  • 缺点:暂无,最推荐使用。

  • 特点:这种方式跟饿汉式方式采用的机制类似,但又有不同。

  • 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

八、枚举

/**

  • 枚举
    */
    public enum King {
    KINGINSTANCE;
    }

  • 优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

  • 缺点:JDK 1.5之后才能使用。

九、容器类管理

/**

  • 使用容器实现单例模式(可以用于管理单例,有兴趣的可以尝试一下)
  • */
    class InstanceManager {
    private static Map<String, Object> objectMap = new HashMap<>();
    private InstanceManager(){}
    public static void registerService(String key,Object instance){
    if (!objectMap.containsKey(key)){
    objectMap.put(key,instance);
    }
    }
    public static Object getService(String key){
    return objectMap.get(key);
    }
    }

/**

  • 使用方式
  • Dog类就不贴出来了
  • 自己随便写个就行
  • 可以运行一下看看 打印的地址是否一致
    */
    class Test {
    public static void main(String[] args) {

InstanceManager .registerService(“dog”, new Dog());

Dog dog = (Dog) InstanceManager .getService(“dog”);
Dog dog2 = (Dog) InstanceManager .getService(“dog”);
Dog dog3 = (Dog) InstanceManager .getService(“dog”);
Dog dog4 = (Dog) InstanceManager .getService(“dog”);

System.out.println(dog);
System.out.println(dog2);
System.out.println(dog3);
System.out.println(dog4);
}
}

  • 优点:在程序的初始,将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作, 降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。

  • 缺点:不常用,有些麻烦

九种写法的优劣对比;

①:不可用原因:由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统运行效率降低,而JDK 1.5 以及之后的版本都修复了这个问题。(面试装逼用,谨记!!!)

②:这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用, 而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

单例模式在Android源码中的应用

在我们每天接触的Android源码中其实也有很多地方用到了单例模式:

1、EventBus中获取实例:

private static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

02416)]

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-Lr3fab7B-1713681102419)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值