单例模式
有很多关于单例模式的博客,书上也有些介绍,了解它也算挺久了。但是部觉得少了点什么,怕自己记了,也怕自己后面找起来麻烦,所以还是写一篇博客来记录一下吧。
单例模式的概念
我的认识是这样,可能不是非常标准,一点自己的想法,不想copy而已:
- 只有一个实例
- 构造方法为
private
, 无法被直接实例化;类中持有一个本类的静态私有对象,并提供静态方法给外界提供访问。
实现方式
不同的方式有不同应用场景,可以按需要选择。其实我还是有个小小的疑问,就是关于饿汉式,instance
实例化的时机是当前类被引用的时候,可以认为是在调用getInstance()
的时候 ,此时类中的变量按照相应的初始化顺序,依次初始化。这样的话,就和懒汉式的效果是一样的了=.=可能是我的想法不太对吧
饿汉式
即初始化类的时候就创建好实例,不用担心多线程的环境下出现问题,但是有可能浪费资源。
1 | public class SingletonHangry { |
懒汉式
即在被需要时才创建实例,这在并发的环境下会出现一些问题。
- 不加任何措施
脑洞一下,都知道这个不一定是只有一个实例。1
2
3
4
5
6
7
8
9class SingletonLazy {
private SingletonLazy(){}
private static SingletonLazy instance;
public static SingletonLazy getInstance(){
if (instance == null)
instance = new SingletonLazy();
return instance;
}
} - 加上同步锁
虽然这样就保证了只有一个实例,但是这个同步锁在每次调用getInstance()
时都会工作,而显然这些同步工作中非常大的一部分是不需要的。所以在性能上必定会有所损失。1
2
3
4
5
6
7
8
9class SingletonLazy {
private SingletonLazy(){}
private static SingletonLazy instance;
public synchronized static SingletonLazy getInstance(){
if (instance == null)
instance = new SingletonLazy();
return instance;
}
} - Double Check Lock(DCL)
说起这个,我刚开始的时候只了解到这有两个if
。后来才知道这就是大名鼎鼎的DCL,失敬失敬!至于那个关键字1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class SingletonLazy {
private SingletonLazy(){}
private static volatile SingletonLazy instance;
public static SingletonLazy getInstance(){
if (instance == null) { // 使用这个if是为了在instance已被初始化之后,避免同步
synchronized (SingletonLazy.class) {
if (instance == null) {
// 这个if是为了因为,如果同时有两个进程A,B执行了getInstance(),它们是都会有机会通过第1个if,
// 也就是说会依次执行同步锁里面的内容。因此没有这个if也是有可能不能保证单例的。
instance = new SingletonLazy();
}
}
}
return instance;
}
}volatile
,与Java中的内存模型有关,加上了这个才能保证单例。它大致做的事情是这样的:instance = new SingletonLazy()
并非是原子操作,事实上在JVM中这句话做了三件事:
1.给instance分配内存
2.调用SingletonLazy()的构造函数来初始化成员变量
3.将instance对象指向分配的空间(执行完这一步instance就不为null)
但是在JVM的即时编译器中存在指令重排序的优化,也就是说上面的第二步和第三步是不能保证顺序的,最终执行的顺序可能是1-2-3或者是1-3-2。如果是后者,则在3执行完毕,2执行之前,被线程2抢占了,这时instance已经是非null了(但却没有初始化),所以线程2会直接返回instance,然后使用,然后会报错。使用了volatile
就保证了:取操作必须在执行完1-2-3之后或者1-3-2之后,不存在执行到1-3然后取到值的情况。
静态内部类
因为类的初始化是虚拟机保证只加载一次,因此是线程安全的。1
2
3
4
5
6
7
8
9class SingletonStaticInnerClass {
static class SingletonHolder {
private final static SingletonStaticInnerClass instance = new SingletonStaticInnerClass();
}
private SingletonStaticInnerClass(){}
private static SingletonStaticInnerClass getInstance(){
return SingletonHolder.instance;
}
}枚举
枚举的相信息:http://blog.csdn.net/u013256816/article/details/505629051
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18enum SingletonEnum {
INSTANCE1, INSTANCE2;
class Singleton {
private Singleton(){}
}
private Singleton instance;
private SingletonEnum(){
instance = new Singleton();
}
public Singleton getInstance() {
return instance;
}
}
public static void main(String[] args) {
SingletonEnum.INSTANCE1.getInstance();
SingletonEnum.INSTANCE2.getInstance();
}
容器
这个有点迷