设计模式之单例模式的7种写法
2016-01-19 11:01
393 查看
一、概述
在介绍单例模式的写法之前,我们有必要了解一下什么是单例模式。 单例模式是一种常用的软件设计模式,在他的核心结构中只包含一个被称为 单例的特殊类。通过单例模式可以保证系统只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。单例模式结构图
二、代码
下面我们来看看单例模式的各种写法以及简单的介绍:1.饿汉式
public class Singleton { private static Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } }
这种方式在类加载时就完成了对象的初始化,所以类加载比较慢,但是获取对象的速度比较快。这种方式可以避免多线程的同步问题,但是我们并不确定这个对象是否需要加载,所以没有达到懒加载的效果。
2.懒汉式(线程不安全)
public class Singleton { private static Singleton singleton ; public static Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }
这种方式采用了懒加载模式,在第一次使用时才去初始化对象,节省了资源,但是第一次使用时需要初始化,反映稍微慢一些,同时会产生线程安全的问题。
3.懒汉式(线程安全)
public class Singleton { private static Singleton singleton ; public static Singleton getInstance(){ synchronized (Singleton.class) { if(singleton == null){ singleton = new Singleton(); } } return singleton; } }
或者
public class Singleton { private static Singleton singleton ; public synchronized static Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }
这种方式可以在多线程环境下安全工作,但是每次调用getInstance()方法都要进行同步,造成不必要的开开销,而且大部分时候我们是用不到同步的,所以不建议采用这种方式。
4.双重检查式(DCL:Double-checked locking)
public class Singleton { private static Singleton singleton; public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
这种写法在getInstance()方法中进行了两次空判断,第一次是为了避免不必要的同步,第二次是在singleton为空的情况下才创建实例。DCL虽然在一定程度上解决了资源的消耗和多余的同步,线程安全等问题,但是在某些情况下会出现DCL失效。在某些书中建议使用静态内部类单例模式来代替DCL.
5.静态内部类单例模式
public class Singleton { public static Singleton getInstance() { return SingletonHolder.singleton; } private static class SingletonHolder { private static final Singleton singleton = new Singleton(); } }
首先需要明确一个结论:加载一个类时,其内部的类不会同时被加载,当且仅当某个静态成员(静态成员变量,构造方法,静态方法)被调用时才去加载。第一次加载Singleton时并不会初始化singleton,只有第一次掉用那个getInstance()方法时才会加载SingletonHolder,并且初始化singleton,这样不仅能够保证线程的安全性也能保证Singleton类的唯一性,所以推荐使用这种方式。
6.枚举单例
public enum Singleton{ INSTANCE; public void doSomething(){ } }
你可以通过Singleton.INSTANCE来访问,比较方便,线程安全,防止反序列化创建新的对象,但是失去了一些类的特性,没有延迟加载,而且可读性较差,所以很少有人使用。
7.容器式
public class SingletonManager { public static Map<String, Object> objMap = new HashMap<String, Object>(); public static void registerService(String key,Object instance){ if(!objMap.containsKey(key)){ objMap.put(key, instance); } } public static Object getService(String key){ return objMap.get(key); } }
用SingletonManager将多个单例统一进行管理,使用时根据key获取对应的实例,这种方式可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,屏蔽了内部的实现细节,降低了耦合度。
相关文章推荐
- Spring task @Async执行失败原因分析
- C++ primer 学习笔记(第二章:变量和基本类型)
- 常用Android开发组件之列表类组件
- git工作流
- C++实现停车场管理系统
- 腾讯防刷负责人:基于用户画像大数据的电商防刷架构 - 本文出自BI168大数据社区,更多精彩请点击 原文地址:http://www.bi168.cn/>>http://www.bi168.cn/th
- selenium调用chrome
- CDH权限不够,修改用户和用户组为root
- GC Roots
- writeb(), writew(), writel(),readb(), readw(), readl() 宏函数
- linux的mount(挂载)命令详解
- 【转】ios输入框被键盘挡住的解决办法
- exports 和 module.exports 的区别
- semanage: 未找到命令
- DataGuard主备归档存在gap的处理办法
- android基本架构
- Mysql 常见问题
- mac通过终端命令删除文件
- Android的传感器开发技术
- QuartzCore框架学习-CAEmitterLayer