设计模式-单例 | 8lovelife's life
0%

设计模式-单例

记录下单例模式的几种实现

单例模式

单例类保证在系统中始终只有一份类的实例,单例模式能够节约内存空间,对于整个系统中共性的逻辑可以采用单例模式。分布式系统中ZK就像是整个系统中的”单例”

单例的实现

单例的实现方式有多种,根据实例化时机可分为饿汉、懒汉模式

饿汉模式

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private static final Singleton singleton = new Singleton();

private Singleton() {
}

public static Singleton getInstance() {
return singleton;
}
}

单例在类的加载时就完成了类的实例(即使这个类还没被使用)

懒汉模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private static Singleton singleton;

private Singleton() {
}

public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

double check 既保证了类的延迟加载,又降低了synchronize带来的累积性能消耗。但这个单例在多线程环境下存在安全隐患

指令重排序

singleton = new Singleton(); 这段代码并非原子操作(开辟内存空间->类的初始化->引用变量赋值),为了提高性能,程序会进行指令的重排序如(开辟内存空间->引用变量赋值->类的初始化),多线程环境下会存在线程拿到未实例完成的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private volatile static Singleton singleton;

private Singleton() {
}

public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

volatile禁止指令重排序

静态内部类

1
2
3
4
5
6
7
8
9
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

只有在调用getInstance()时才会加载静态内部类SingletonHolder(JVM保证类的加载是线程安全的),从而实例化Singleton

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public enum Singleton {
INSTANCE;

Object object;

Singleton() {
object = new Object();
}

public Object getInstance() {
return object;
}
}

Mac:src mac$ javac -encoding utf-8 Singleton.java
Mac:src mac$ javap -c Singleton.class
Compiled from "Singleton.java"
public final class Singleton extends java.lang.Enum<Singleton> {
public static final Singleton INSTANCE;

java.lang.Object object;

public static Singleton[] values();
Code:
0: getstatic #1 // Field $VALUES:[LSingleton;
3: invokevirtual #2 // Method "[LSingleton;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LSingleton;"
9: areturn

public static Singleton valueOf(java.lang.String);
Code:
0: ldc #4 // class Singleton
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class Singleton
9: areturn

public java.lang.Object getInstance();
Code:
0: aload_0
1: getfield #9 // Field object:Ljava/lang/Object;
4: areturn

static {};
Code:
0: new #4 // class Singleton
3: dup
4: ldc #10 // String INSTANCE
6: iconst_0
7: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #12 // Field INSTANCE:LSingleton;
13: iconst_1
14: anewarray #4 // class Singleton
17: dup
18: iconst_0
19: getstatic #12 // Field INSTANCE:LSingleton;
22: aastore
23: putstatic #1 // Field $VALUES:[LSingleton;
26: return
}

public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable

枚举类的字节码可以看出,枚举在使用的时候(懒加载)触发类的初始化(线程安全),枚举类已经实现了序列化接口

Life’s a little bit messy. We all make mistakes. - Judy Hopps

Zootopia