博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之单例模式
阅读量:5749 次
发布时间:2019-06-18

本文共 3058 字,大约阅读时间需要 10 分钟。

1. 概念:

某个类有且仅有一个实例,通过自行实例化向整个系统提供这个实例,这种设计模式被称作单例模式。复制代码

2. 特点:

1. 单例类只能有一个实例2. 单例类必须自己创建自己的唯一实例3. 单例类必须给所有其他对象提供这一实例复制代码

3. 关键点:

1. 构造函数私有化2. 通过一个静态方法或枚举返回单例对象3. 确保单例类的对象有且仅有一个,特别是多线程环境下4. 确保单例类在反序列化时不会重新构建对象复制代码

4. 实现方式:

4.1 饿汉式

public class Singleton {    private static Singleton instance = new Singleton();        private Singleton() {            }        public static Singleton getInstance() {        return instance;    }}复制代码
在单例类初始化时,已经自行实例化,所以饿汉式单例是线程安全的,每次获取单例对象时直接返回该实例,这样节省时间,但由于实例本身是静态的,会一直占据内存空间。复制代码

4.2 懒汉式

public class Singleton {    private static Singleton instance;        private Singleton() {            }        public synchronized Singleton getInstance() {        if (instance == null) {            instance = new Singleton();        }        return instance;    }}复制代码
只有在使用时才会进行实例化,此种方式实现是线程不安全的,虽然在一定程度上节省了内存空间,但同时导致时间的损耗,而且每次调用getInstance时都进行同步,造成不必要的同步开销。复制代码

4.3 Double Check Lock (DLC)

public class Singleton {    private static Singleton instance;        private Singleton() {            }        public static Singleton getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new Singleton();                }            }        }        return instance;    }}复制代码
DLC方式实现单例既能够在需要时才会实例化,又能保证线程安全,在实例化之后调用getInstance不再进行同步锁。另外,上述代码中instance = new Singleton()语句,实际并不是一个原子操作,它可以分为三个步骤:1. 给Singleton的实例分配内存;2. 调用Singleton的构造函数,初始化成员变量;3. 将instance对象指向分配的内存空间(此时instance != null)。但是由于Java编译器允许处理器乱序执行,在JDK1.5之前的JVM中,上述2和3的执行顺序是无法保证的,也就是说执行顺序有可能是1-2-3或者1-3-2。如果是后者的话,在多线程并发的情况下就有可能出错。在JDK1.5之后可以使用volatile关键字,保证instance对象每次都是从主内存中读取。复制代码

4.4 静态内部类单例模式

public class Singleton {    private Singleton() {            }        public static Singleton getInstance() {        return SingletonHolder.instance;    }        private static class SingletonHolder {        private static final Singleton instance = new Singleton();    }}复制代码
此方式的单例在第一次加载Singleton类时并不会实例化,只有第一次调用getInstance方法时才会实例化。第一次调用getInstance会导致虚拟机加载SingletonHolder类,这种方式既能确保线程安全,也能保证对象唯一,同时也延迟了单例的实例化,这是推荐使用的单例模式实现方式。复制代码

4.5 枚举单例

public enum Singleton {    INSTANCE;}复制代码
默认枚举实例的创建都是线程安全的,并且在任何情况下都是只有一个实例。其他方式的单例,在反序列化后readObject方法会返回一个新实例,枚举单例不存在此问题,其他方式的单例可以通过重写readResolve方法避免:复制代码
private Object readResolve() throws ObjectStreamException {    return instance;}复制代码

4.6 使用容器实现单例

public class SingletonManager {    private static HashMap
map = new HashMap(); private SingletonManager() { } public static void registerService(String key, Object instance) { if (!map.containsKey(key) { map.put(key, instance); } } public static Object getService(String key) { return map.get(key); }}复制代码
在程序的初始,将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象。这种方式可以管理多种类型的单例,并且可以在使用时可以通过统一的借口进行获取,降低了使用成本,也隐藏了具体实现,降低耦合度。例如Android系统中,使用context获取系统级别的服务,就是用的该方式复制代码

注意:

单例对象如果持有Context,很容易引发内存泄漏,最好使用Application Context。复制代码

#####参考资料: 《Android源码设计模式解析与实战》

转载于:https://juejin.im/post/5b7e2856518825284910c7f4

你可能感兴趣的文章
RAID及mdadm命令
查看>>
众安:保险业的超级大脑
查看>>
图片保存
查看>>
eclipse导出项目为war提示Module name is invalid
查看>>
《Spring Boot 实战:从0到1》第3章 零XML配置的Spring Boot Application
查看>>
linux几个命令 ll结果说明, linux chmod 0777含义, chmod 和 chown区别
查看>>
Python---字典方法
查看>>
服务器灌包与抓包
查看>>
配置IIS以运行外部访问
查看>>
海康萤石摄像机远程监控机制分析
查看>>
SpringCloud微服务实战(四)-微服务中的服务拆分
查看>>
mock 使用方法
查看>>
json字符串还原map
查看>>
MyBatis:The expression 'list' evaluated to a null value
查看>>
node web模块 (服务器端和客户端)
查看>>
记一次oracle数据库redolog全部丢失的恢复
查看>>
《Effective C++》
查看>>
Fiddler更新日志
查看>>
Servlet监听器笔记总结
查看>>
公开/封闭属性android:exported引出的Android系统安全技术
查看>>