内容简介:Singleton单例模式是最简单的设计模式,它的主要作用是保证在程序运行生命周期中,使用了单例模式的类只能有一个实例对象存在。单例模式实现了类似C语言中全局变量的功能,单例模式常用于注册/查找的服务。单例模式的UML图如下:单例模式有两种实现方式:饱汉模式和饿汉模式,如下:
Singleton单例模式是最简单的设计模式,它的主要作用是保证在程序运行生命周期中,使用了单例模式的类只能有一个实例对象存在。单例模式实现了类似 C语言 中全局变量的功能,单例模式常用于注册/查找的服务。
单例模式的UML图如下:
单例模式有两种实现方式:饱汉模式和饿汉模式,如下:
1.饱汉单例模式例子代码:
public class Singleton1{ //饱汉模式,声明时就创建实例对象 public static final Singleton1 instance = new Singleton1(); //单类模式的构造方法必须为private,以避免通过构造方法创建对象实例, //并且必须显示声明构造方法,以防止使用默认构造方法 private Singleton1(){} //单类模式必须对外提供获取实例对象的方法 public static Singleton1 geInstance(){ return instance; } } 2.饿汉单例模式即延迟初始化单例方式,例子代码: public class Singleton2{ //饿汉模式,声明时不创建实例对象 public static Singleton2 instance; //单类模式的构造方法必须为private,以避免通过构造方法创建对象实例, //并且必须显示声明构造方法,以防止使用默认构造方法 private Singleton2(){} //单类模式必须对外提供获取实例对象的方法,延迟初始化的单类模式必须使用synchronized同步关键字,否则多线程情况下很容易产生多个实例对象 public static synchronized Singleton2 geInstance(){ //延迟初始化,只有当第一次使用时才创建对象实例 if(instance == null){ instance = new Singleton2(); } return instance; } } 一般认为饱汉模式要比饿汉模式更加安全。 上面两种Singleton单例 设计模式 的实现方式都隐藏有如下的问题: (1).虽然构造方式的访问修饰符为private,即除了自身以外其他任何类都无法调用,但是通过反射机制的setAccessiable(true)方法可以访问私有方法和属性。因此Singleton单例模式必须考虑这种例外情况。 (2).对象序列化之后再反序列化时会生成新的对象,因此当Singleton单例模式类实现序列化接口时,必须显式声明所有的字段为tranisent,并且提供如下的readResolve方法来防止通过序列化破坏单态模式: private Object readResolve(){ return INSTANCE; } 3.使用Lazy initialization holder class模式实现单态: public class Singleton3 { /** * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 */ private static class SingletonHolder{ //静态初始化器,由JVM来保证线程安全 private static Singleton3 instance = new Singleton3(); } //私有化构造方法 private Singleton3(){ } public static Singleton3 getInstance(){ return SingletonHolder.instance; } } 当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会被虚拟机在装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。 这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。 4.在JDK1.5之后引入了Enum枚举,因此在JDK1.5之后Singleton单例模式又有了第三种实现方式,也是最好的实现方式,例子如下: public enum Singleton4{ INSTANCE{ public void doSomething(){ ... } }; public abstract void doSomething(); } Singleton单例模式中只有一个INSTANCE枚举元素,枚举可以保证真个程序生命周期中只有一个实例对象存在,同时还避免了常规Singleton单例模式private构造方法被反射调用和序列化问题(枚举提供了序列化保证机制,确保多次序列化和反序列化不会创建多个实例对象)。 注意:java中除了构造方法可以创建对象实例以外,还可以通过克隆方法(clone()是Object中的protected方法)来创建对象,若单例对象直接继承自Object对象,则如果没有提供具体clone方法实现,则当调用克隆方法创建对象时,会抛出运行时的异常CloneNotSupportedException。 若单例类继承了实现克隆方法的类,则在单例类中必须覆盖父类的克隆方法,显式抛出异常CloneNotSupportedException。 另外,实现了单例模式的类不能再有派生子类,因为构造方式是私有的,子类无法调用父类构造方法,因此达到了Final的效果。 JDK的中单例模式的应用: java.lang.Runtime 单例模式的优点: * 在内存中只有一个对象,节省内存空间。 * 避免频繁的创建销毁对象,可以提高性能。 * 避免对共享资源的多重占用。 * 可以全局访问。 适用场景:由于单例模式的以上优点,所以是编程中用的比较多的一种设计模式。我总结了一下我所知道的适合使用单例模式的场景: * 需要频繁实例化然后销毁的对象。 * 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。 * 有状态的 工具 类对象。 * 频繁访问数据库或文件的对象。 * 以及其他我没用过的所有要求只有一个对象的场景。 单例模式注意事项: * 只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。 * 不要做断开单例类对象与类中静态引用的危险操作。 * 多线程使用单例使用共享资源时,注意线程安全问题。 关于 java 中单例模式的一些争议: 单例模式的对象长时间不用会被jvm垃圾收集器收集吗? 看到不少资料中说:如果一个单例对象在内存中长久不用,会被jvm认为是一个垃圾,在执行垃圾收集的时候会被清理掉。对此这个说法,我持怀疑态度我的观点是:在hotspot虚拟机1.6版本中,除非人为地断开单例中静态引用到单例对象的联接,否则jvm垃圾收集器是不会回收单例对象的。 在一个jvm中会出现多个单例吗? 在分布式系统、多个类加载器、以及序列化的的情况下,会产生多个单例,这一点是无庸置疑的。那么在同一个jvm中,会不会产生单例呢?使用单例提供的getInstance()方法只能得到同一个单例,除非是使用反射方式,将会得到新的单例。代码如下 复制代码
Class c = Class . forName ( Singleton . class . getName ( ) ) ; Constructor ct = c . getDeclaredConstructor ( ) ; ct . setAccessible ( true ) ; Singleton singleton = ( Singleton ) ct . newInstance ( ) ; 复制代码
note:免费的才是最贵的
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Designing Web Navigation
James Kalbach / O'Reilly Media / 2007-8-15 / USD 49.99
Thoroughly rewritten for today's web environment, this bestselling book offers a fresh look at a fundamental topic of web site development: navigation design. Amid all the changes to the Web in the pa......一起来看看 《Designing Web Navigation》 这本书的介绍吧!