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()方法,每个线程调用时,输出当前序列号。
联系客服