1.定义:单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,一个类只有一个对象实例。 2.结构:
3.实现 1)饿汉模式:不管有没有使用,对象都已经创建了; 1 // 饿汉式单例
2 public class Singleton {
3 // 私有构造
4 private Singleton() {}
5 // 饿汉模式对象从开始就已经创建了
6 private static Singleton single = new Singleton();
7 // 静态工厂方法
8 public static Singleton getInstance() {
9 return single;
10 }
11 }
饿汉式单例在类加载初始化就创建好了一个静态的对象供外部使用,除非系统重启,这个对象不会改变,所以本身就是线程安全的。Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效) 2)懒汉模式:如果未调用,对象不会创建,只有被使用时,创建对象。 1 // 懒汉式单例(不考虑多线程情况)
2 public class Singleton {
3 // 懒汉模式对象在使用时才进行创建
4 private static Singleton instance ; // 将构造器私有化
5 private Singleton() {}
6 // 提供公开的方法获取当前类的对象
7 public static Singleton getInstance() {
8 // 判断对象是否存在,如果不存在new
9 if(instance==null) {
10 instance = new Singleton();
11 }
12 return instance;
13 }
14 }
该示例虽然用延迟加载方式实现了懒汉式单例,但在多线程环境下会产生多个single对象。 3)使用双重校验锁实现 1 // 有同步锁效果的懒汉模式
2 public class Singleton {
3 private static volatile Singleton instance = null;
4 private Singleton() {}
5 public static Singleton getInstance() {
6 // 双重检查
7 if (instance == null) {
8 // 相当于对getInstance()进行了同步锁
9 synchronized (Singleton.class) {
10 if (instance == null) {
11 instance = new SingletonB();
12 }
13 }
14 }
15 return instance;
16 }
17 }
在方法上加synchronized同步锁或是用同步代码块对类加同步锁,此种方式解决了多个实例对象问题,使用双重检查进一步做了优化,可以避免整个方法被锁,只对需要锁的代码部分加锁,可以提高执行效率。 4.特点 i. 单例类只能有一个实例; ii.单例类必须自己创建自己的唯一实例; iii.单例类必须给所有其他对象提供这一实例; 5.优缺点 优点: 1)在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2)避免对资源的多重占用(比如写文件操作)。 缺点: 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。 6.适用环境 i.一个全局使用的类频繁地创建或销毁 ii.要求生产唯一序列号 iii.web中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来 iv.创建的一个对象需要消耗的资源过多,比如IO与数据库的连接等 v.在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以由若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。 7.应用 通过单例模式实现唯一序列号效果,有一个类Singleton,有一个静态属性i,这个属性从1开始,当调用sequence()方法时,自增1。模拟一个多线程效果,有10个线程调用Singleton类的sequence()方法,每个线程调用时,输出当前序列号。 |
|