单例模式

利用类加载机制的饿汉单例模式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package singleton;

/**
* Created by hero on 17-2-20.
*/
public class Singleton {
public static Singleton instance() {
return Inner.s;
}

private static class Inner {
private static Singleton s = new Singleton();
}

private 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
65
66
67
68
69
70
71
72
package common;

/**
* Created by carl on 5/1/17.
*/
public class SingletonA {
private SingletonA() {
System.out.println("instance A: " + this.hashCode());
}

private static class SingletonHolder {
private static final SingletonA s = new SingletonA();
}

public static SingletonA getInstance() {
return SingletonHolder.s;
}

public void fun() {
System.out.println("hello");
}
}

package common;

/**
* Created by carl on 5/1/17.
*/
public enum SingletonB {
INSTANCE;

void fun() {
System.out.println("singletonB: " + this.hashCode());
}
}

package common;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
* Created by carl on 5/1/17.
*/
public class UseCase {
public static void main(String[] args) {
try {
// enum 单例用法
SingletonB.INSTANCE.fun();

Class clazz = SingletonB.class;
Object[] cs = clazz.getEnumConstants();
Method m = clazz.getDeclaredMethod("fun");
m.invoke(cs[0]);
Object[] cs2 = clazz.getEnumConstants();
Method m2 = clazz.getDeclaredMethod("fun");
m2.invoke(cs2[0]);

SingletonA singletonA = SingletonA.getInstance();
singletonA.fun();

Class clazz2 = SingletonA.class;
Constructor constructor = clazz2.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonA singletonA1 = (SingletonA) constructor.newInstance();
singletonA1.fun();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

通过UseCase可以发现,SingletonA是可以通过反射获取多个实例的,而enum单例却不能通过反射产生多个实例。