单例模式也叫做单件模式,单例模式最主要的用途就是用来确保程序中一个类最多只有一个实例。
单例模式的定义如下:
确保一个类只有一个实例,并提供一个全局访问点。
由定义可知,单例模式主要用于程序中某些对象只能有一个实例,如果制造多个实例就会导致许多问题产生,例如程序的行为异常,资源使用过量,或者是不一致的结果,所以单例模式常常被用来管理共享的资源例如数据库的连接或者线程池等等。
单例模式使用也是非常简单,单例模式的类图是所有模式的类图最简单的,但尽管设计简单,实际使用时还是会遇到许多问题。
在Java中实现单件模式需要一个私有的构造器,一个静态方法和一个静态变量即可。
最常见的单例模式实现如下:
public class Singleton { /** * (1)声明一个静态变量用来记录本类的唯一实例,注意它是私有的,静态的。 */ private static Singleton instance; /** * (2)私有的构造函数确保了只有本类内才可以调用构造器来实例化对象。 */ private Singleton(){} /** * (3)实例化本类对象并返回这个实例,注意这是一个类方法, * 程序中的任何地方都可以通过调用Singleton.getInstance() * 来多的Singleton的唯一实例化对象。 * @return 本类对象instance */ public static Singleton getInstance(){ if (instance==null) {//如果instance是null的,表示还没有创建实例;如果instance不为null说明之前已经创建过对象,直接return即可。 instance=new Singleton();//在这里注意如果我们不需要这个instance实例,它就永远不会产生,这个就叫做“延迟实例化”。 } return instance; } }
以上是一个经典的单例模式声明过程,上面的代码中提到了“延迟实例化”概念,通俗点就是只有在用的时候才去实例化,还用一种“急切实例化”的单例模式,如果你想要实现单例的类在创建和运行时的负担并不繁重你可以考虑这种方式,代码模版如下:
public class Singleton { private static Singleton instance=new Singleton();//在静态初始化中就创建单例,同时避免多线程的问题。 private Singleton(){} public static Singleton getInstance(){ return instance;//直接返回此单例。 } }
在经典的单例模式中可以发现它有一个很大的弊端,那就是它并不适合多线程的情况,在多线程中使用经典的单例模式这套代码可能出现不止一个对象,要解决这个多线程的问题就得使用下面的”双重检查加锁“的单例模式,代码模版如下:
public class Singleton { /* * volatile确保当instance变量被初始化成Singleton实例时, * 多个线程正确的处理instance变量。 */ private volatile static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if (instance==null) {//如果instance为null,就进入同步区。 synchronized (Singleton.class) {//只有第一次才执行到这里的代码 if (instance==null) {//再次检查,如果仍是空,那么创建实例。 instance=new Singleton(); } } } return instance; } }
以上是三种单例模式的实现模版,在实际开发中可根据需求适当选择使用那种模版。如果对对多线程没有要求,同时getInstance()的性能对应用程序不是很关键时使用”延迟实例化“的单例模式,如果应用程序总是创建并使用单例或者在创建和运行时的负担并不繁重使用“急切实例化”的单例模式,如果对多线程有要求,而且性能是你关心的重点那就使用”双重检查加锁“的单例模式。