定义:确保一个类只有一个实例,并提供一个全局访问点。 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; | |
} | |
} |