首页 > 代码库 > 设计模式-单例模式

设计模式-单例模式

1 模式动机

   在软件系统中,时常会有一些对象只能存在一个,而且需要在全局共享使用。如果不同地方调用的对象不同,那么很可能操作的数据或界面就会混乱,造成严重的影响。

2 模式定义

   单例模式(Singleton Pattern): 确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。

3 饿汉式单例(经常使用)

预先加载,在类加载时完成单例对象的初始化。

实例代码:

 1 package com.pattern.singleton.preload;
 2 
 3 
 4 // 饿汉式单例,在类初始化时,已经实例化
 5 
 6 public class Singleton {
 7 
 8     private static final Singleton instance = new Singleton();
 9 
10     // 私有化构造方法,使不能在别的类创建对象
11 
12     private Singleton() {}
13 
14 
15    // 对外提供一个获取该实例的方法
16 
17     public static Singleton getInstance() {
18 
19         return instance;
20 
21     }
22 
23 }

 

   饿汉式在类加载时就已创建单例,以后不再改变,天生是线程安全的。

定义饿汉式单例包含以下几点:

    1 将采用单例模式的类构造方法私有化(private修饰)

    2 内部实例化的对象通过private static final修饰,避免对象再次变化

3 定义一个静态方法返回单例

优点:写起来比较简单,而且不存在多线程问题。

缺点:在类加载时就会分配内存,即便还没有使用到该单例,也会占用内存。

 

4 饿汉式进化版(较少使用)

 1 package com.pattern.singleton.preload.version1;
 2 
 3 //饿汉式单例,在类初始化时,已经实例化
 4 public class Singleton {
 5     private Singleton() {
 6         // 私有构造器,统一外部访问单例对象方式(getInstance)
 7     }
 8 
 9     public static Singleton getInstance() {
10         return SingletonHolder.instance;
11     }
12 
13     private static class SingletonHolder {
14         private static final Singleton instance = new Singleton();
15     }
16 }

 

 

5 懒汉式单例(单线程场景使用)

延迟加载,在第一次调用getInstance()时初始化。

实例代码:

 1 package com.pattern.singleton.delayload;
 2 
 3 public class Singleton {
 4     private static Singleton instance = null;
 5 
 6     private Singleton() {}
 7 
 8     public static Singleton getInstance() {
 9         if(instance==null) {
10             instance = new Singleton();
11         }
12         return instance;
13     }
14 }

优点:写起来比较简单,当类加载时,实例未被创建,当外部调用时,创建实例。

缺点:多线程场景可能出现多个实例,只能用于单线程场景。

 

6 懒汉式进化版1(经常使用)

   因为懒汉式单例存在线程安全问题,所以产生进化版1

 1 package com.pattern.singleton.delayload.version1;
 2 
 3 public class Singleton {
 4     private static Singleton instance = null;
 5 
 6     private Singleton() {}
 7 
 8     public static synchronized Singleton getInstance() {
 9         if(instance==null) {
10             instance = new Singleton();
11         }
12         return instance;
13     }
14 }

优点:使用synchronized,线程安全。

缺点:当getInstance()频繁调用时,效率略低。

 

7 懒汉式进化版2(经常使用)

 1 package com.pattern.singleton.delayload.version2;
 2 
 3 public class Singleton {
 4     // 使用volatile,避免instance还未初始化完成时,被其它线程调用
 5     private static volatile Singleton instance = null;
 6 
 7     private Singleton() {
 8         // 私有构造器,统一外部访问单例对象方式(getInstance)
 9     }
10 
11     public static Singleton getInstance() {
12         if (instance == null) {
13             synchronized (Singleton.class) {
14                 if (instance == null) {
15                     instance = new Singleton();
16                 }
17             }
18         }
19         return instance;
20     }
21 }

上面的实现代码为最佳实现。内存占用低,效率高,线程安全,多线程操作原子性。

 

8 优缺点

优点:

1 提供唯一的对象供全局访问,保证了对象内容的唯一性。

缺点:

1 使用过多时,如果实现不规范,可能导致内存无法释放,造成内存泄露。

 

9 适用环境

1 如果某个对象只能存在一个,并且需要在全局共享,那么通过单例模式实现。

 

10 总结

1 关于对象,能不用单例尽量不用单例。因为当系统越来越复杂,单例使用越来越多时,稍微处理不当,就可能产生内存泄露。如果对象包含数据或配置,必须保持唯一性,再采用单例实现。

设计模式-单例模式