单例模式大致可以分为两类,懒汉模式和饿汉模式,但是不必在意是懒还是饿,还是要明白他们的原理和区别。(什么是懒汉,就是类加载了之后,并没有实例化单例,而是延后到第一次使用的时候;什么事恶汉,就是类加载了,就实例化单例了。)

本文所举例均为线程安全的单例模式。

直接看代码和注释:

1、双重加锁的单例模式(懒汉模式)

这种模式也是作者之前最常使用的模式,因为代码好理解,并且是lazyload模式,不会产生垃圾对象。基本面试的时候也会首先回答这种模式,这种模式可以延伸出好多知识点,包括volatile的作用,synchronized锁。

/*** 双层加锁的单例模式* */
public class SingletonTest3 implements Test{/*** instance使用volatile修饰,防止线程之间出现脏数据,导致线程A已经执行完instance = new SingletonTest3() ;* 后线程B拿到锁,但是判断instance还是null,而导致instance初始化两次。*/private volatile static SingletonTest3 instance = null ;private SingletonTest3(){Log.d("gggl" , "SingleTest3 初始化了") ;}public static SingletonTest3 getInstance(){//首先进行instance的null判断,为了在没有线程竞争的情况下提高速度不必进行锁的竞争。if (instance == null) {//加锁防止线程竞争synchronized (SingletonTest3.class) {//二次判断,这里是必须的,因为第一个null判断不是线程安全的。if (instance == null) {instance = new SingletonTest3() ;}}}return instance ;}@Overridepublic void test() {Log.d("gggl" , "SingletonTest3 初始化了") ;}
}

2、static final 修饰成员变量instance(恶汉模式)

这种模式下,当我们的class被加载到内存中后,就会调用构造函数,如果你的单例项目启动后就一直需要的话,采用这种方式没有任何问题,简单方便。但是如果你的单例是项目启动后需要某些动作触发才需要的话,不建议采用这种方式,浪费一丢丢内存。其实也有点吹毛求疵了哈,不过这是面试,认真点。-^-

import com.example.interview.Test;public class SingletonTest1 implements Test {private SingletonTest1(){Log.d("gggl" , "SingletonTest1 初始化了")  ;}private static final SingletonTest1 instance = new SingletonTest1() ;public static SingletonTest1 getInstance() {return instance ;}public void test(){Log.d("gggl" , "SingletonTest1 say hello!!!!") ;}
}

3、静态内部类模式(懒汉模式)

静态内部类模式。这种模式略显负责,作者也是不喜欢使用,因为我基本都是采用第一种的双重null判断模式。但是没办法出去面试,都是看看。


public class SingletonTest1 implements Test {private SingletonTest1(){Log.d("gggl" , "SingletonTest1 初始化了")  ;}public static SingletonTest1 getInstance() {return SingletonHander.singleton ;}public void test(){Log.d("gggl" , "SingletonTest1 say hello!!!!") ;}private static class SingletonHander{private static final SingletonTest1 singleton = new SingletonTest1 ();}
}

测试代码:

try {Class.forName("com.example.interview.designpattern.SingletonTest1" , true , getClassLoader()) ;Log.d("gggl" , "SingletonTest1加载完毕") ;Class.forName("com.example.interview.designpattern.SingletonTest2" , true , getClassLoader()) ;Log.d("gggl" , "SingletonTest2加载完毕") ;Class.forName("com.example.interview.designpattern.SingletonTest3" , true , getClassLoader()) ;Log.d("gggl" , "SingletonTest3加载完毕") ;SingletonTest1.getInstance().test();SingletonTest2.getInstance().test();SingletonTest3.getInstance().test();} catch (ClassNotFoundException e) {e.printStackTrace();}

这里首先对SingletonTest的几个类进行了加载(注:Class.forName进行加载类的时候顺便执行了初始化的一些任务,具体执行到哪些步骤作者没有具体看jdk代码,但是static成员变量和代码块都是在这个阶段执行的)。然后分别调用SingletonTest.getInstance().test()方法。下面我们来看执行结果。

2022-09-16 10:16:01.081 11710-11710/com.example.interview D/gggl: SingletonTest1 初始化了
2022-09-16 10:16:01.081 11710-11710/com.example.interview D/gggl: SingletonTest1加载完毕
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingletonTest2加载完毕
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingletonTest3加载完毕
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingletonTest1 say hello!!!!
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingletonTest2 初始化了
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingletonTest2 say hello!!!!
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingleTest3 初始化了
2022-09-16 10:16:01.082 11710-11710/com.example.interview D/gggl: SingletonTest3 初始化了

大家看到了SingletonTest1也就是饿汉模式的第一种(private static final SingletonInstance1 = new SingletonInstance1())在类加载的时候就执行了构造函数,这就是区别,面试知识点。

总结:

其实以上三种模式大家在开发的时候只需固定化使用1或者3即可,第二种因为不是lazyload模式所以尽量不要使用,好的编码习惯也是需要点滴养成的。而针对面试知道上面三种模式足够了,至于那种线程不安全的最简单的模式就不要往出写了,没任何意义。

2022面试Android之单例模式相关推荐

  1. 2022面试Android之ThreadLocal

    主要功能: 针对一个对象,每个线程需要存储不同的值的时候,使用ThreadLocal会非常的方便. 图解: 针对一个全局变量local,线程1-4都持有local的引用.当线程分别对local进行修改 ...

  2. 面试android开发工程师小结

    5-25 今天面试了家公司,2个大神,差不多进行了1.5小时.不过最终还是没有录取,可能我的项目经验缺乏,能力不达标. 今天问的问题大致如下,凭记忆写的,反正就那样吧: 1.android servi ...

  3. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第六章:数据存储

    第 6 章 数据存储 本章介绍Android 4种存储方式的用法,包括共享参数SharedPreferences.数据库SQLite.存储卡文 件.App的全局内存,另外介绍Android重要组件-应 ...

  4. Android设计模式——单例模式(Singleton)

    二十三种设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元 ...

  5. 腾讯面试Android高级岗。居然被一个多线程基础面倒了?

    前言 一个在深圳从事开发五年的老友一个月前从原公司辞职后,昨天去腾讯总部面试Android高级岗,一面的时候,自我介绍后,陆陆续续问了很多问题,有着五年的从业经验很多项目开发的技术问题都回答的很通顺, ...

  6. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第五章:中级控件

    第 5 章 中级控件 本章介绍App开发常见的几类中级控件的用法,主要包括:如何定制几种简单的图形.如何使用几种选择按钮.如何高效地输入文本.如何利用对话框获取交互信息等,然后结合本章所学的知识,演示 ...

  7. 2022 最新 Android studio添加阿里云Aliyun Maven仓库

    2022 最新 Android studio添加阿里云Aliyun Maven仓库 网上看了很多的文章,都是老文章,要不就是AS是老版本,我是个新手,也不懂AS老了有啥好的,所以下载AS的时候,默认就 ...

  8. 2022年Android中高级面试框架

    目录 Java 泛型 集合 ArrayList LinkedList HashMap LinkedHashMap ConcurrentHashMap 多线程并发 volatile 线程 反射 JVM ...

  9. 2022中级Android开发面试解答,当上项目经理才知道

    缘起 随着互联网企业的不断发展,产品项目中的模块越来越多,用户体验要求也越来越高,想实现小步快跑.快速迭代的目的越来越难,还有65535,应用之间的互相调用等等问题,插件化技术应用而生.如果没有插件化 ...

最新文章

  1. 全局变量引起的BUG
  2. Java 集合框架,看这篇真的够了!
  3. 中缀表达式计算、后缀表达式计算、中缀转后缀
  4. nemesis什么车_nemesis是什么意思_nemesis的翻译_音标_读音_用法_例句_爱词霸在线词典...
  5. puppet语法学习
  6. 设计模式:观察者(Observer)模式
  7. 今日头条把微信按在地上摩擦
  8. 如何在Android中获取当前时间和日期
  9. 辨异 —— 概率与统计
  10. 向视图中插入的数据能进入到基本表中去吗?_数据库调优,调的是什么及常见手法...
  11. setpythonhome_python的set,和字典的详细使用方法,以及部分习题
  12. 基于Java springmvc+mybatis酒店信息管理系统设计和实现
  13. ChineseBERT Chinese Pretraining Enhanced by Glyph and Pinyin Information
  14. jy在线制图系统免费源码丨一秒生成广告横图海报图
  15. GeForce Desktop Products Compute Capability
  16. java创建临时文件
  17. 对啊英语音标---四、双元音常见的字母发音组合有哪些
  18. arm -linux开发产品,arm是什么意思_arm的翻译_音标_读音_用法_例句_爱词霸在线词典...
  19. 20169220 网络攻防实践 第二周学习总结
  20. 邮箱自动化(smtplib模块)--以邮件正文HTML表格形式

热门文章

  1. 二阶常系数非齐次线性微分方程待定系数法求特解
  2. 人工智障也刷题!Kaggle 入门之实战泰坦尼克号
  3. 新编计算机英语第2版,新编计算机英语-电子教案2.ppt
  4. 在Geany里配置python3的方法!!!含window10下载Geany过程
  5. EEG-fMRI同步记录的伪影去除法
  6. 百融金服获2亿B轮融资 打造融合线上线下基因的第三方金融大数据公司
  7. Nest+Vue实战:工作计划管理系统
  8. VXGI体素全局照明
  9. 查验身份证 浙大陈越习题
  10. pci串行端口找不到驱动程序_PCI网卡和PCIE网卡