单例模式定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
使用场景:
1. 要求生成唯一序列号的环境;
2. 在整个项目种需要一个共享访问点或共享数据;
3. 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
4. 需要定义大量的静态变量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。
创建单例一般分为三步:
1. 私有静态静态类引用;
2. 私有构造方法;
3. 对外公开静态方法getInstance;
单例的具体实现分为两种,他们都有着自己的名字,一个叫饿汉式单例,另一个叫做懒汉式单例。
饿汉式单例比较好实现我们先来看一下它的代码。
public class Emperor {
//初始化一个皇帝
private static final Emperor emperor = new Emperor();
//私有构造方法
private Emperor() {
}
//对外公开获取单例方法
public static Emperor getInstance(){
return emperor;
}
//...
}
懒汉式单例,实现稍微复杂一点,他去要考虑线程安全。先来一个线程不安全的例子:
public class Emperor {
//初始化一个皇帝
private static Emperor emperor = null;
//私有构造方法
private Emperor() {
}
//对外公开获取单例方法
public static Emperor getInstance(){
if(emperor == null){
emperor = new Emperor();
}
return emperor;
}
//...
}
下面我们来分析一下,如我一个线程走到了emperor = new Emperor();这一步但是还没有实例化好对象,此时emperor == null,这个时候又有一个线程过来,他一看if(emperor == null)这个条件,满足,那他就也进来了,这样就出现了两个单例。修改后的代码如下
public class Emperor {
//初始化一个皇帝
private static Emperor emperor = null;
//私有构造方法
private Emperor() {
}
//对外公开获取单例方法
public static Emperor getInstance() {
if (emperor == null) {
synchronized (Emperor.class) {
if (emperor == null) {
emperor = new Emperor();
}
return emperor;
}
}
return emperor;
}
//...
}
扩展,那我们能不能实现规定好多少个实例的多例模式呢?比如说,我想要来一个类,只能实例化两个对象。
可以!
public class Emperor {
//定义最多能产生的实例变量
private static int maxNumOfEmperor = 2;
//每个皇帝都有名字,使用一个ArrayList(如果考虑线程安全可用Vector)来容纳,每个对象的私有属性
private static List<String> nameList = new ArrayList<String>();
//定义一个列表容纳所有的实例
private static List<Emperor> emperorList = new ArrayList<Emperor>();
//当前皇帝的序号
private static int countNumOfEmperor = 0;
//产生所有的对象
static {
for(int i=0; i<maxNumOfEmperor; i++){
emperorList.add(new Emperor("皇帝" + (i+1)));
}
}
private Emperor(){
}
//传入私有属性
private Emperor(String name){
nameList.add(name);
}
//这里取得哪一个实例
public static Emperor getInstance(int num){
if(num >= maxNumOfEmperor)
num=0;
return emperorList.get(num);
}
}
有上限的多例模式,可以让我们在设计时决定在内存中有多少个实例,方便系统进行扩展修正单例可能存在的性能问题,提供系统响应速度。