设计模式4——单例模式


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个月前写好的,结果一晃一个季度过去了却还未修改发布。执行力不够,容易被琐碎的事情给耗尽了……

嗯,进步空间还是非常大滴!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值