定义:确保一个类只有一个实例,并提供一个全局访问点。 Head First设计模式第五章

要点:

  • 单件模式确保程序中一个类最多只有一个实例。
  • 单件模式也提供访问这个实例的全局点。
  • 在 java 中实现单件模式需要私有的构造器、一个静态方法和一个静态变量。
  • 确定在性能和资源上的限制,然后小心地选择适当的方案来实现单件,以解决多线程的问题(我们必须认定所有的程序都是多线程的)。
  • JDK1.4 版本及之前,双重检查加锁实现会失效。
  • 如果使用多个类加载器,可能导致单件失效而产生多个实例。每个类加载器定义了一个命名空间,如果有两个以上,不同的类加载器可能会加载同一个类,从而产生多个单件并存的怪异现象。
  • 如果使用 jvm1.2 或之前的版本,你必须建立单件注册表,以免垃圾收集器将单件回收。
  • 通俗讲的饿汉式和懒汉式,指的就是单件的急切实例化和延迟实例化。
  • 全局变量比单件模式差,全局变量可能造成命名空间的污染,不能确保只有一个实例。

单件实现方式一:非线程安全

package com.example.pattern.singleton;
 
/**
 * <p>
 * <code>Singleton</code>
 * </p>
 * Description: 线程不安全,在多线程环境下可能创建多个实例
 *
 * @author Mcchu
 * @date 2018/1/17 14:27
 */
public class Singleton {
 
    /**
     * 单件变量
     */
    private static Singleton uniqueInstance;
 
    /**
     * 声明私有构造器
     */
    private Singleton(){ }
 
    /**
     * 外部调用方法
     * @return uniqueInstance
     */
    public static Singleton getInstance(){
        if ( uniqueInstance==null ){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

单件模式实现方式二:线程安全,性能低

package com.example.pattern.singleton;
 
/**
 * <p>
 * <code>SingletonThreadSafeRepeat</code>
 * </p>
 * Description: 线程安全,但是降低了性能,因为只有第一次创建单件时才需要做线程控制
 *
 * @author Mcchu
 * @date 2018/1/17 15:13
 */
public class SingletonThreadSafeRepeat {
 
    /**
     * 单件变量
     */
    private static SingletonThreadSafeRepeat uniqueInstance;
 
    /**
     * 私有构造器
     */
    private SingletonThreadSafeRepeat(){};
 
    /**
     * 对外公开
     * @return uniqueInstance
     */
    public static synchronized SingletonThreadSafeRepeat getInstance(){
        if ( uniqueInstance==null ){
            uniqueInstance = new SingletonThreadSafeRepeat();
        }
        return uniqueInstance;
    }
}

单件模式实现方式三:饿汉式 - 急切创建

package com.example.pattern.singleton;
 
/**
 * <p>
 * <code>SingletonThreadSafe</code>
 * </p>
 * Description: 线程安全 -> 依赖 jvm 在加载这个类时马上创建此唯一的单件实例
 *
 * @author Mcchu
 * @date 2018/1/17 14:47
 */
public class SingletonThreadSafe {
 
    /**
     * “急切” 创建实例(又称饿汉式),
     */
    private static SingletonThreadSafe uniqueInstance = new SingletonThreadSafe();
 
    /**
     * 声明私有构造器
     */
    private SingletonThreadSafe(){}
 
    /**
     * 直接使用上面创建的实例
     * @return uniqueInstance
     */
    public static SingletonThreadSafe getInstance(){
        return uniqueInstance;
    }
}

单件模式实现方式四:双重检查加锁

package com.example.pattern.singleton;
 
/**
 * <p>
 * <code>SingletonDoubleLockThreadSafe</code>
 * </p>
 * Description: 双重加锁 ->double-checked locking,线程安全
 *
 * @author Mcchu
 * @date 2018/1/17 14:49
 */
public class SingletonDoubleLockThreadSafe {
 
    /**
     * JDK1.4 及更早版本,JCM 对于 volatile 关键字的实现会导致双重检查加锁失效,所以不要用此方法实现
     */
    private volatile static SingletonDoubleLockThreadSafe uniqueInstance;
 
    /**
     * 私有构造器
     */
    private SingletonDoubleLockThreadSafe(){};
 
    public static SingletonDoubleLockThreadSafe getInstance(){
        if ( uniqueInstance==null ){
            // 注意,这里是在不存在时进入同步区块
            synchronized ( SingletonDoubleLockThreadSafe.class ){
                if ( uniqueInstance==null ){
                    uniqueInstance = new SingletonDoubleLockThreadSafe();
                }
            }
        }
        return uniqueInstance;
    }
}