常用的设计模式-单例设计模式

Posted 程序员的故事会

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常用的设计模式-单例设计模式相关的知识,希望对你有一定的参考价值。


单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。

单例模式有以下特点

 
   
   
 
  1. 1.单例类只能有一个实例

  2. 2.单例类必须自己创建自己的唯一实例

  3. 3.单例类必须给所有其他对象提供这一实例

基本实现思路

 
   
   
 
  1. a.构造函数私有化,防止外部调用

  2. b.内部提供一个静态的方法返回该类的引用

下面介绍几种单例模式的写法

饿汉式
 
   
   
 
  1. public class SingletonUtil {

  2. private static SingletonUtil mInstance = new SingletonUtil();


  3. private SingletonUtil() {}


  4. public static SingletonUtil getInstance() {

  5. return mInstance;

  6. }

  7. }

说明:简单易懂,不存在线程同步问题,随着类的加载,对象也被一并创建。但是若这个类自始至终都没有使用,则会造成内存浪费

懒汉式(一)
 
   
   
 
  1. public class SingletonUtil1 {


  2. private static SingletonUtil1 mInstance;


  3. private SingletonUtil1() {}


  4. public static SingletonUtil1 getInstance() {

  5. if (mInstance == null) {

  6. mInstance = new SingletonUtil1();

  7. }

  8. return mInstance;

  9. }

  10. }

说明:只有在使用时才创建对象,仅在单线程中使用,多线程中还是会创建多个实例,不能保证只有一个实例

懒汉式(二)
 
   
   
 
  1. public class SingletonUtil1 {


  2. private static SingletonUtil1 mInstance;


  3. private SingletonUtil1() {}


  4. public static SingletonUtil1 getInstance(){

  5. synchronizedSingletonUtil1.class){

  6. if (mInstance == null) {

  7. mInstance = new SingletonUtil1();

  8. }

  9. }

  10. return mInstance;

  11. }

  12. }

说明:解决了上一个方法中线程不安全的问题,即多线程会创建多个实例,但是效率低下,每次获取的对象时,都需要经过同步锁

懒汉式(三)
 
   
   
 
  1. public class SingletonUtil1 {


  2. private static volatile SingletonUtil1 mInstance;


  3. private SingletonUtil1() {}


  4. public static SingletonUtil1 getInstance() {

  5. if (mInstance == null) {

  6. synchronized (SingletonUtil1.class) {

  7. if (mInstance == null) {

  8. mInstance = new SingletonUtil1();

  9. }

  10. }

  11. }

  12. return mInstance;

  13. }

  14. }

说明:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。在mInstance上添加了volatile,其目的防止重排序,也保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的

静态内部类
 
   
   
 
  1. public class SingletonUtil2 {

  2. private SingletonUtil2() {}


  3. public static SingletonUtil2 getInstance() {

  4. return SingletonUtil1Holder.mInstance;

  5. }


  6. public static class SingletonUtil1Holder {

  7. static volatile SingletonUtil2 mInstance = new SingletonUtil2();

  8. }


  9. }

说明:静态内部类不会随着外部类的加载而加载 ,只有静态内部类的静态成员被调用时才会进行加载,所以在你第一次调用getInstance()之前,SingletonUtil1Holder是没有被装载进来的,只有在你第一次调用了getInstance()之后,里面涉及到了return SingletonUtil1Holder.mInstance, 产生了对SingletonUtil1Holder的引用,内部静态类的实例才会真正装载,这里就是懒加载。由于静态内部类的特性,只有在其被第一次引用的时候才会被加载,所以可以保证其线程安全性

容器管理(参考获取系统服务的代码)

 
   
   
 
  1. public class SingletonUtil3 {

  2. private final static String name = "SingletonUtil3";

  3. private static Map<String, SingletonUtil3> mSingletonMap = new HashMap<>();


  4. static {

  5. mSingletonMap.put("", new SingletonUtil3());

  6. }


  7. private SingletonUtil3() {}


  8. public static SingletonUtil3 getInstance() {

  9. return mSingletonMap.get(name);

  10. }

  11. }

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

结束语

文中介绍了几种单例的写法,具体可结合自身项目去考虑使用那种方式去实现。也还有其他的方式来实现,比如枚举等,都是其实现的思路是一样的,保证构造私有,提供一个公有的方法获取类的引用。

以上是关于常用的设计模式-单例设计模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之单例模式

常用设计模式之单例

前端常用设计模式之单例模式

单例设计模式

java:常用的两种设计模式(单例模式和工厂模式)

设计模式之单例模式