专栏首页秦子帅设计模式(1)-单例模式
原创

设计模式(1)-单例模式

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。

image

普通的单例模式写法如下:

//只有内部类可以为static。
 public class Singleton{
     //在自己内部定义自己的一个实例,只供内部调用  
        private static final Singleton instance = new Singleton(); 
            private Singleton(){ 
                } 
                //这里提供了一个供外部访问本class的静态方法,可以直接访问    
   public static Singleton getInstance(){  
          return instance;  
             } }

单例模式的优点

(1).由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。

(2).由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,比如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决。

(3).单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。

(4).单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。


单例模式的缺点

(1).单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。

(2).单例对象如果持有Context,那么很容易引发内存泄露,此时需要注意传给单例对象的Context最好是Application Context。


单例模式的七种写法

1.(懒汉,线程不安全):

public class Singleton {  
      private static Singleton instance;  
      private Singleton (){}   
      public static Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
     return instance;  
     }  
 }

这种写法在多线程不能正常工作。

2.(懒汉,线程安全):

public class Singleton {  
      private static Singleton instance;  
      private Singleton (){}
      public static synchronized Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
}

这种写法能够在多线程中很好的工作,但是效率很低,99%情况下不需要同步。

3.(饿汉):

public class Singleton {  
    private static Singleton instance = new Singleton();  
     private Singleton (){}
     public static Singleton getInstance() {  
     return instance;  
     }  
 }

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。这种写法能够在多线程中很好的工作,但是每次调用getInstance方法时都需要进行同步,造成不必要的同步开销,而且大部分时候我们是用不到同步的。

4. 双重检查模式 (DCL)

public class Singleton {  
      private volatile static Singleton singleton;  
      private Singleton (){}   
      public static Singleton getSingleton() {  
      if (singleton == null) {  
          synchronized (Singleton.class) {  
          if (singleton == null) {  
              singleton = new Singleton();  
          }  
         }  
     }  
     return singleton;  
     }  
 }

这种写法在getSingleton方法中对singleton进行了两次判空,第一次是为了不必要的同步,第二次是在singleton等于null的情况下才创建实例。DCL优点是资源利用率高,第一次执行getInstance时单例对象才被实例化,效率高。缺点是第一次加载时反应稍慢一些,而且有失效的可能。

5. 静态内部类

public class Singleton {  
      private static class SingletonHolder {  
      private static final Singleton INSTANCE = new Singleton();  
      }  
      private Singleton (){}
      public static final Singleton getInstance() {  
          return SingletonHolder.INSTANCE;  
      }  
  }

第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingletonHolder 并初始化sInstance ,这样不仅能确保线程安全也能保证Singleton类的唯一性,很合理的单例模式。

6. 枚举

public enum Singleton {  
     INSTANCE;  
     public void whateverMethod() {  
     }  
 }

7. 使用容器

public class SingletonManager { 
   private static Map<String, Object> objMap = new HashMap<String,Object>();//使用HashMap作为缓存容器  
    private Singleton() { 
       }  
public static void registerService(String key, Objectinstance) { 
       if (!objMap.containsKey(key) ) { 
       objMap.put(key, instance) ;//第一次是存入Map 
           } 
             }  
public static ObjectgetService(String key) {  
       return objMap.get(key) ;//返回与key相对应的对象 
         } }

用SingletonManager 将多种的单例类统一管理,在使用时根据key获取对象对应类型的对象。用户使用时只需要根据key来获取到对应的ServiceFetcher,然后通过ServiceFetcher对象的getService函数获取具体的服务对象。当第一次获取时,会调用ServiceFetcher的creatService函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。Android中的系统核心服务以单例形式存在,减少了资源消耗。


总结:

不管以哪种形式实现单例模式,它们的核心原理是将构造函数私有化,并且通过静态公有方法获取一个唯一的实例,在这个获取的过程中必须保证线程的安全,同时也要防止单例对象的资源消耗。

本文参考的书籍有《设计模式之禅》以及网上博文。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python入门-环境搭建详解(Window平台)

    安装成功后重启电脑,再重新打开Python安装程序就可以了。一定要看好Python的安装路径。

    秦子帅
  • Android-再次解读萤石云视频

    我之前写过一篇萤石云的集成文章,很多人问我有没有demo, 今天我再次总结一下, 并加个些功能。

    秦子帅
  • Okhttp3源码解析(3)-Call分析(整体流程)

    想起来了吧?无论是get还是post请求 都要生成call对象,在上面我们发现call实例需要一个okHttpClient与request实例 ,我们先点进C...

    秦子帅
  • java单例模式之我看

    神秘的寇先森
  • Java 单例的五种写法

    单例的目的是为了保证某个类只实例化一个对象。对于我们来说,理解这些单例写法的不同点,最好的方法是明白他们在什么情况下会失效。

    PhoenixZheng
  • 单例模式的八种写法

    单例模式作为日常开发中最常用的设计模式之一,是最基础的设计模式,也是最需要熟练掌握的设计模式。单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访...

    王金龙
  • 如何写出一个性能优化的单例模式

    单例模型是面试当中最常见的一种设计模式,它是一种对象创建模式,用于产生一个对象的具体实例,可以确保系统中一个类只产生一个实例。

    朱季谦
  • 设计模式二十四章经之单例设计模式

    我就是马云飞
  • 写了这么久代码,你懂单例模式吗?

    这种方式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。这种方式基于类加载机制避免了多线程的同步问题,但是也不能确定有其他的方式(或者其他的静态方...

    咻咻ing
  • 从实例出发,了解单例模式和静态块

    什么是单例模式呢,单例模式(Singleton)又叫单态模式,它出现目的是为了保证一个类在系统中只有一个实例,并提供一个访问它的全局访问点。从这点可以看出,单例...

    古时的风筝

扫码关注云+社区

领取腾讯云代金券