设计模式-单件模式

工程中,某些对象我们只需要一个,比如线程池,缓存,对话框等的对象,我们通常的做法是可以定一个全局静态变量,然后通过程序初始化的时候就实例化他们,然后直接调用这个全局变量,但是这样有个问题,如果我的这个对象消耗的资源很多,而有的时候,我的程序在运行过程中又没用到这个对象,岂不是浪费了很多资源。通常的做法就是定义全局静态变量的时候,不初始化他,而是在调用过程中实例化,这样的话,对于全局变量的实例化,我们就要判断这个变量是否已经实例化了,如果实例化了的吧,我们就不对它进行实例化,所以代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class A
{
private A(){}
public static A cla;
public static A getInstance()
{
if (cla == null){
cla=new A();
}
return cla;
}
}

这里的A的构造器是私有的,这样子可以有效的保证A这个类不会再外部被实例化,从而保证他的唯一性,我们通过getInstance来获取A的全局唯一变量cla,这样就有效的解决了上面这个问题,但是问题又来了,多线程访问getInstance()的时候?cla完全可能出现实例化一次之后又被实例化,怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
public class A
{
private A(){}
public static A cla;
public static synchronized A getInstance()
{
if (cla == null){
cla=new A();
}
return cla;
}
}

我们就为A获取实力的方法getInstance增加一个同步锁来保证方法只能被唯一访问,可是,同步锁势必会降低运行效率,而且我们发现,事实上,也就是第一次实例化的时候会出现问题需要同步锁,以后再需要获取这个对象的时候完全不需要,如果我们频繁的获取对象的话,效率的影响就会相当大。回到最开始的做法?设置全局变量,程序运行的时候就实例化对象?

1
2
3
4
5
6
7
8
9
public class A
{
private A(){}
public static A cla = new A();
public static synchronized A getInstance()
{
return cla;
}
}

这个确实是种方法,但始终不是最好的方法,我们想到,之前所说的,只有在实例化的时候才需要同步锁,那么我们就想到采用双重检查加锁的方法,只在实例化的时候加锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class A
{
private A(){}
public volatile static A cla;
public static A getInstance()
{
if (cla == null){
synchronized(A.class){
if (cla==null){
cla=new A();
}
}
}
return cla;
}
}

其中volatile的关键字是确保多线程在cla变量初始化的时候,正确的处理cla变量。(volatile用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A))