保证一个类仅有一个实例,并提供一个访问他的全局访问点。
所有类都有构造方法,假如不对他进行编码,系统会生成空的public的构造方法,外部类就能创建这个类的对象。为了不让其他类能new出这个类的实例,所以需要写一个private的构造方法(其实即使使用private修饰,通过反射机制还是能在外部调用的)。然后再提供一个返回该类实例的函数供外部调用。
当一个事物只能出现一个实例的时候,我们就能用到他,举例。
当一个系统只能出现一个控制类的时候;当一个系统只能有一个数据库连接池的时候;资源管理器只能有一个实例;
根据单例模式的定义,写出了一个原型,如下:
public class Singleton1 { private static Singleton1 sInstance = null; private Singleton1() { } public static Singleton1 getInstance() { if (sInstance == null) { sInstance = new Singleton1(); } return sInstance; } }
上面代码有一个问题,没有考虑线程安全的问题。假如在多线程使用这个单例,多个线程可能同时执行到判断是否为空的代码。假如第一次运行,对象就是空的,所以多个线程就同时进入了if语句,然后同时运行创建实例的代码。
针对上面线程安全的问题,很容易就想到了锁,于是乎,代码编程下面这样:
public class Singleton2 { private static Singleton2 sInstance = null; private Singleton2() { } public static Singleton2 getInstance() { if (sInstance == null) { synchronized (Singleton2.class) { sInstance = new Singleton2(); } } return sInstance; } }
第2份代码有一个问题,假如多个线程同时通过了是否为空的判断,他们仍然会串行的执行创建实例的代码。所以我们还得改,于是又想到把同步的范围扩大,如下面代码:
public static Singleton3 getInstance() { synchronized (Singleton3.class) { if (sInstance == null) { sInstance = new Singleton3(); } } return sInstance; }
这样处理的话,每次调用getInstance()函数都需要执行一次同步,同步锁是很耗时的,所以每次调用这个函数耗时都会很长,降低了性能。我们要做到的是第一次调用的时候,避免多次创建,所以,我们可以用双重锁来处理这个。
public class Singleton3 { private static Singleton3 sInstance = null; private Singleton3() { } public static Singleton3 getInstance() { if (sInstance == null) { synchronized (Singleton3.class) { if (sInstance == null) { sInstance = new Singleton3(); } } } return sInstance; } }
对于序列化功能的支持,防止序列化前后的不一致,我们作如下处理。
public Object readResolve() { return getInstance(); }
根据以上的分析和优化,我们得到了一个基本符合要求的单例模式的代码。单例模式有常用的两种写法“懒汉式”和“饿汉式”,下面是“懒汉式”:
public class SingletonL { private static SingletonL sInstance = null; private SingletonL() { } public static SingletonL getInstance() { if (sInstance == null) { synchronized (SingletonL.class) { if (sInstance == null) { sInstance = new SingletonL(); } } } return sInstance; } public Object readResolve() { return getInstance(); } }
下面的是“饿汉式”写法:
public class SingletonE { private static final SingletonE sInstance = new SingletonE(); private SingletonE() { } public static SingletonE getInstance() { return sInstance; } public Object readResolve() { return getInstance(); } }
“懒汉式”顾名思义,我比较懒,我要的时候你就要给我,所以创建实例是在getInstance()函数里面。
“饿汉式”表明我很饿,所以你需要立刻给我,于是在申明的时候就需要创建实例。
下面我们来看看如何调用:
SingletonE singletonE = SingletonE.getInstance(); singletonE.print(); SingletonL singletonL = SingletonL.getInstance(); singletonL.print();
代码下载地址:https://github.com/bird7310/DesignPatternExample.git
这一篇本是3个月前写好的,结果一晃一个季度过去了却还未修改发布。执行力不够,容易被琐碎的事情给耗尽了……
嗯,进步空间还是非常大滴!
原文地址:http://blog.csdn.net/mtt1987/article/details/38796149