1解释
1.1定义
保证一个类仅有一个实例,并提供一个访问他的全局访问点。
1.2分析
所有类都有构造方法,假如不对他进行编码,系统会生成空的public的构造方法,外部类就能创建这个类的对象。为了不让其他类能new出这个类的实例,所以需要写一个private的构造方法(其实即使使用private修饰,通过反射机制还是能在外部调用的)。然后再提供一个返回该类实例的函数供外部调用。
1.3使用场景
当一个事物只能出现一个实例的时候,我们就能用到他,举例。
当一个系统只能出现一个控制类的时候;当一个系统只能有一个数据库连接池的时候;资源管理器只能有一个实例;
2代码实例
根据单例模式的定义,写出了一个原型,如下:
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总结
这一篇本是3个月前写好的,结果一晃一个季度过去了却还未修改发布。执行力不够,容易被琐碎的事情给耗尽了……
嗯,进步空间还是非常大滴!