单例模式

  1. 适用范围:当一个类只需要一个实例时,可以考虑采用单例模式,但并不是所有的类都适合做成单例,如果一个类含有数据(也即是有状态的类),那么将该类做成单例时可能会引发线程安全问题(多个线程同时对数据操作),此时的解决之道是要么将该数据做成只读(创建时写入数据),要么不做成单例,做成单例的类要尽量保证是无状态的。
  2. 单例模式可以分为强制型单例非强制型单例(也有人叫管理上的单例),这两种单例是我自己命名的,前一种单例是让coder代码上不能轻易(Java中可以通过反射机制创建对象)创建对象,只能使用单例模式提供的获取对象的方法,非强制性单例代码上不对coder做强制性限制,要求自觉。
  3. 多线程安全强制型单例模式的实现方式
    饿汉式:

     // 饿汉式
     public class Singleton {
    
         private static Singleton instance = new Singleton();
         private Singleton() {
             // empty
         }
         public static Singleton getInstance() {
             return instance;
         }
     }
    
    

    双检测锁机制的单例模式:

     // 双检测锁机制的单例模式
     public class Singleton {
    
         private static Singleton instance = null;
         private Singleton() {
             // empty
         }
         public static Singleton getInstance() {
             if (instance == null) {
                 synchronized (Singleton.class) {
                     if (instance == null) {
                         instance = new Singleton();
                     }
                 }
             }
             return instance;
         }
     }
    

    还有一种懒汉式的实现方法,不过不满足多线程安全,只能在单线程下使用

  4. 多线程安全非强制性单例模式的实现方式

     public class Singleton {
         // empty
     }
    
    
     import java.util.HashMap;
     import java.util.Map;
    
     public class BeanFactory {
    
         public static Map<String, Object> beans = new HashMap<String, Object>();
         private static BeanFactory instance = new BeanFactory();
    
         private BeanFactory() {
             // empty
         }
         public static BeanFactory getInstance() {
             return instance;
         }
    
         public Object getBean(String id) {
             if (beans.containsKey(id)) {
                 return beans.get(id);
             } else if (id.equals(Singleton.class.getSimpleName())) {
                 synchronized (Singleton.class) {
                     if (!beans.containsKey(id)) {
                         beans.put(id, new Singleton());
                     }
                 }
                 return beans.get(id);
             }
             return null;
         }
     }
    
    
  5. 单例模式还有范围的概念,即在某一范围内才是单例,范围扩大了可能就不是单例了,常见的单例范围有application级别,session级别,request/response级别。
    小技巧:可以利用thread的thread号为关键字存入HashMap来实现thread级别的单例。