zoukankan      html  css  js  c++  java
  • 单例模式笔记

    单例模式


    • 多线程的线程池的底层设计一般采用单例模式。

    • web应用的配置对象采用单例模式,因为配置文件是共享的资源。

    • 网站的计数器,应用的计数器。

    • 应用程序的日志应用一般采用单例模式,由于共享的日志文件一直处于打开状态,所以只能有一个实例去操作。

    • 数据库的连接池的设计一般采用单例模式,数据库资源的打开或关闭非常消耗资源,所以用单线程维护。

      单例模式的七种写法


      第一种 懒汉式,线程不安全

      定义一个指针,使用时用 getInstance 方法获取,线程不安全

      public class Singleton {
          private Singleton instance;
        private Single(){}
          public static Singleton getInstance(){
            if(instance == null){
                  instance = new Singleton();
              }
              return instance;
          }
      }
      
      第二种 懒汉式,线程安全

      适合多线程情况,但是效率低

      public class Singleton{
          private static Singleton instance;
          private Single(){}
          public static synchronized Singleton getInstance(){
              if(instance == null){
                  instance = new Singleton();
              }
              return instance;
          }
      }
      
      第三种 饿汉式

      这种方式基于classloader机制避免了多线程的同步问题,没有lazy loading

      public class Singleton{
          private static Singleton instance = new Singleton();
          private Singleton (){}
          public static Singleton getInstance(){
              return instance;
          }
      }
      
      第四种 饿汉式2.0

      类似第三种,在类初始化时就实例化instance

      public class Singleton{
          static {
              instance = new Singleton();
          }
          private Singleton(){}
          public static Singleton getInstance(){
              return this.instance;
          }
      }
      
      第五种 静态内部类

      利用 classloader 的机制来保证初始化instance时只有一个线程,跟第三种和第四种的细微差别是:第三种和第四种是只要Singleton被装载了,那么instance就会被实例化(未实现lazy loader),而这种方式是Singleton类被装载了,instance不一定被初始化,因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方式,才会显示装载SingletonHolder类,从而实例化instance。相对于第三四种的方式填补的缺点。

      1. 实例化instance很消耗资源
      2. 不希望在Singleton类装载时就实例化
      public class Singleton{
          private static class SingletonHolder{
              private static final Singleton INSTANCE = new Singleton();
          }
          private Single(){}
          public static final Singleton getInstance(){
      		return SingletonHolder.INSTANCE;
          }
      }
      
      第六种 枚举

      此种方式是Effective Java 作者Josh Bloch 提倡的方式,它可以避免多线程同步问题,并且能够防止反序列化重新创建新的对象,

      public enum Singleton {
          INSTANCE;
          public void whateverMethod(){
          }
      }
      
      第七种 双重校验锁

      第二种的升级版,俗称双重检查锁定

      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;
          }
      }
      
      问题
      1. 如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例,假定不是远端存取,例如一些servlet 使用完全不同的类,装载器,这样会有两个servlet访问单例类
      2. 如果Singleton 实现了java.io.Serializable 的接口,那么这个类的实例就可能被序列化和复原,如果序列化一个,二复原多个,那么就会有多个单例对象
      解决

      1

      private static Class getClass (String classname) throw ClassNotFoundException {
          ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
          if(classLoader == null) classLoader = Singleton.class.getClassLoader();
          return (classLoader.loadClass(className));
      }
       
      

      2

      public class Singleton implements java.io.Serializable {
          public static Singleton INSTANCE = new Singleton();
          
          protected Singleton(){}
          private Object readResolve(){
              return INSTANCE;
          }
      }
      
      
      总结

      第四种和第三种类似,第一种不算,所以,一般五种写法,懒汉,饿汉,双重校验锁,枚举,静态内部类。

  • 相关阅读:
    C++细节3
    C++细节2
    C++细节1
    连通域标记方法
    dll动态链接库入门2
    UnixShell编程(第三版)
    Xcode 快捷键
    mysql在linux上的一点操作
    mysql 语句
    开机自动启动
  • 原文地址:https://www.cnblogs.com/xido/p/14602058.html
Copyright © 2011-2022 走看看