单例模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。
单线程版本
懒汉模式 & 饿汉模式
懒汉模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Singleton { // 定义一个空的 Singleton 对象引用 SINGLETON private static Singleton SINGLETON = null;
// 利用构造器私有化来限制外部使用 new 关键字,进而避免构造出多个实例 private Singleton() { }
// 提供外部获取单例对象的方法 public static Singleton getInstance() { // 如果 SINGLETON 还未指向任何一个 Singleton 对象,new 一个 Singleton 对象出来。 if (SINGLETON == null ) { SINGLETON = new Singleton(); } return SINGLETON; } }
|
对象引用一开始为 null,具体使用的时候才 new 一个对象出来,这种写法属于懒汉模式。
饿汉模式
1 2 3 4 5 6 7 8 9 10 11 12
| public class Singleton {
// 在定义时就直接 new 出单例对象 private static Singleton SINGLETON = new Singleton();
private Singleton() { }
public static Singleton getInstance() { return SINGLETON; } }
|
顾名思义,单例对象一开始就被 new Singleton() 主动构建,不再需要判空操作,这种写法属于饿汉模式。
多线程版本
如果上面『懒汉模式』的代码是运行在多线程环境中,就会出现许多问题。最明显的一个,将有可能 new 出多个 Singleton 对象实例。最简单的修复方式是在 getInstance() 方法上加 synchronize 关键字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Singleton {
private static Singleton SINGLETON = null;
private Singleton() { }
// 方法上加 synchronized 关键字 public synchronized static Singleton getInstance() { if (SINGLETON == null ) { SINGLETON = new Singleton(); } return SINGLETON; } }
|
但是这样的话,不管单例对象有没有构建出来,每次调用 getInstance() 方法的时候都会加锁。 使用 double-checked lock(双检锁) 可以避免在 new 出单例对象之后还对 getInstance() 方法进行加锁,这是对锁粒度细化的一种体现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Singleton {
private static Singleton SINGLETON = null;
private Singleton() { }
public static Singleton getInstance() { // 第一次检查 if (SINGLETON == null) { // 只有 SINGLETON 为 null 时,才对 new Singleton() 代码块进行加锁。 synchronized (Singleton.class) { // 第二次检查 if (SINGLETON == null) { SINGLETON = new Singleton(); } } } return SINGLETON; } }
|
引用