单例模式get

单例模式使用

懒汉式:指全局的单例实例在第一次被使用时构建。

饿汉式:指全局的单例实例在类装载时构建。

直接来懒汉模式↓

1
2
3
4
5
6
7
8
9
10
// Version 1
public class Single1 {
private static Single1 instance;
public static Single1 getInstance() {
if (instance == null) {
instance = new Single1();
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
// Version 2
public class Single1 {
private static Single1 instance;
private Single1() {}
public static synchronized Single1 getInstance() {
if (instance == null) {
instance = new Single1();
}
return instance;
}
}

将构造器改为private的意义在于防止外部类直接调用
加同步锁的意义在于防止多个线程同时获取单例并判断是否为空之后都创新的对象

双重检查(Double-Check)版本

Version2代码相对于Version1代码的效率问题,其实是为了解决1%几率的问题,而使用了一个100%出现的防护盾。那有一个优化的思路,就是把100%出现的防护盾,也改为1%的几率出现,使之只出现在可能会导致多个实例出现的地方。

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

这已经是一个比较完美的单例模式了,最近用大佬代码的时候看到了他这种用单例的方式,就找了原文博客学到了这种双重检查的方法

  • 第一个if (instance == null),其实是为了解决Version2中的效率问题,只有instance为null的时候,才进入synchronized的代码段——大大减少了几率。

  • 第二个if (instance == null),则是跟Version2一样,是为了防止可能出现多个实例的情况。

我以为就这样结束了?还有终极版本volatile

为解决小概率会发生的原子性问题,

// Version 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Single4 {

private static volatile Single4 instance;

private Single4() {}

public static Single4 getInstance() {

if (instance == null) {

synchronized (Single4.class) {

if (instance == null) {

instance = new Single4();
}
}
}

return instance;
}
}