写点什么

深度认识单例模式;在 Android 源码中的应用,华为 Android 面试真题解析

用户头像
Android架构
关注
发布于: 50 分钟前

一、饿汉式(静态常量)


/**


  • 饿汉式(静态常量)*/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;}}


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

  • 缺点


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


:暂无,最推荐使用。


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

  • 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要 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);

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
深度认识单例模式;在Android源码中的应用,华为Android面试真题解析