总结
- 需要解决的问题:
- 避免多个实例造成系统资源浪费
- 避免多个实例之间状态不一致而引起系统故障
- 现在一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,也就是可以让类的外部来通过构造方法创建多个实例。换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。
- 要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。
- 私有化构造方法 &把获取实例的方法变成静态的 & 定义存储实例的属性
- 单例模式的范围
- 也就是在多大范围内是单例呢?
- 观察上面的实现可以知道,目前Java里面实现的单例是一个虚拟机的范围。因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的ClassLoader装载饿汉式实现的单例类的时候就会创建一个类的实例。
- 这就意味着如果一个机器上有多个虚拟机,那么每个虚拟机里面都应该有一个这个类的实例,但是整个机器上就有很多个实例了。
- 另外请注意一点,这里讨论的单例模式并不适用于集群环境,对于集群环境下的单例这里不去讨论,那不属于这里的内容范围。
- 单例模式的命名
- 一般建议单例模式的方法命名为:getInstance()
- 优点
- (1) 单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。
(2) 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
(3) 允许可变数目的实例。基于单例模式我们可以进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例,既节省系统资源,又解决了单例单例对象共享过多有损性能的问题。
- (1) 单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。
- 缺点:
- (1) 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
(2) 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
(3) 现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致共享的单例对象状态的丢失。
- (1) 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
- 饿汉式是线程安全的,因为虚拟机保证了只会装载一次,在装载类的时候是不会发生并发的。
- 当然懒汉式也是可以实现线程安全的,只要加上synchronized即可,如下:
- 饿汉、懒汉结合的实现方式:使用内部类
-
//Initialization on Demand Holder class Singleton { private Singleton() { } private static class HolderClass { private final static Singleton instance = new Singleton(); } public static Singleton getInstance() { return HolderClass.instance; } public static void main(String args[]) { Singleton s1, s2; s1 = Singleton.getInstance(); s2 = Singleton.getInstance(); System.out.println(s1==s2); } }
- 懒汉式实现
-
/** * 懒汉式单例实现的示例 */ public class Singleton { /** * 定义一个变量来存储创建好的类实例 */ private static Singleton uniqueInstance = null; /** * 私有化构造方法,好在内部控制创建实例的数目 */ private Singleton() { // } /** * 定义一个方法来为客户端提供类实例 * * @return 一个Singleton的实例 */ public static synchronized Singleton getInstance() { // 判断存储实例的变量是否有值 if (uniqueInstance == null) { // 如果没有,就创建一个类实例,并把值赋值给存储类实例的变量 uniqueInstance = new Singleton(); } // 如果有值,那就直接使用 return uniqueInstance; } /** * 示意方法,单例可以有自己的操作 */ public void singletonOperation() { // 功能处理 } /** * 示意属性,单例可以有自己的属性 */ private String singletonData; /** * 示意方法,让外部通过这些方法来访问属性的值 * * @return 属性的值 */ public String getSingletonData() { return singletonData; } }
-
- 饿汉式实现
-
/** * 饿汉式单例实现的示例 */ public class Singleton { /** * 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只会创建一次 */ private static Singleton uniqueInstance = new Singleton(); /** * 私有化构造方法,好在内部控制创建实例的数目 */ private Singleton() { // } /** * 定义一个方法来为客户端提供类实例 * * @return 一个Singleton的实例 */ public static Singleton getInstance() { // 直接使用已经创建好的实例 return uniqueInstance; } /** * 示意方法,单例可以有自己的操作 */ public void singletonOperation() { // 功能处理 } /** * 示意属性,单例可以有自己的属性 */ private String singletonData; /** * 示意方法,让外部通过这些方法来访问属性的值 * * @return 属性的值 */ public String getSingletonData() { return singletonData; } }
-
-