首页 > 代码库 > 设计模式-单例模式
设计模式-单例模式
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 关于对象,能不用单例尽量不用单例。因为当系统越来越复杂,单例使用越来越多时,稍微处理不当,就可能产生内存泄露。如果对象包含数据或配置,必须保持唯一性,再采用单例实现。
设计模式-单例模式