Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit abe9250

Browse filesBrowse files
author
zhupeiquan
committed
What_is_an_efficient_way_to_implement_a_singleton_in_Java.md
1 parent 57d785f commit abe9250
Copy full SHA for abe9250

File tree

Expand file treeCollapse file tree

1 file changed

+164
-0
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+164
-0
lines changed
+164Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# 如何创建单例 ?
2+
3+
## 问题
4+
Java 创建单例有哪些方式 ?
5+
6+
## 解答
7+
实现单例,从加载方式来看,有两种:
8+
9+
- 预加载
10+
- 懒加载
11+
12+
先看一下实现单例最简单的方式(预加载):
13+
```
14+
public class Foo {
15+
16+
private static final Foo INSTANCE = new Foo();
17+
18+
private Foo() {
19+
if (INSTANCE != null) {
20+
throw new IllegalStateException("Already instantiated");
21+
}
22+
}
23+
24+
public static Foo getInstance() {
25+
return INSTANCE;
26+
}
27+
}
28+
```
29+
30+
再来看一下懒加载的方式:
31+
```
32+
class Foo {
33+
34+
private static Foo INSTANCE = null;
35+
36+
private Foo() {
37+
if (INSTANCE != null) {
38+
throw new IllegalStateException("Already instantiated");
39+
}
40+
}
41+
42+
public static Foo getInstance() {
43+
if (INSTANCE == null) {
44+
INSTANCE = new Foo();
45+
}
46+
return INSTANCE;
47+
}
48+
}
49+
```
50+
51+
以上方式在单线程的情况可以很好的满足需要,换言之,若是在多线程,还需要作一定的改进,如下所示:
52+
```
53+
class Foo {
54+
// 请注意 volatile 关键字的使用
55+
private static volatile Foo INSTANCE = null;
56+
57+
private Foo() {
58+
if (INSTANCE != null) {
59+
throw new IllegalStateException("Already instantiated");
60+
}
61+
}
62+
63+
public static Foo getInstance() {
64+
if (INSTANCE == null) { // Check 1
65+
synchronized (Foo.class) {
66+
if (INSTANCE == null) { // Check 2
67+
INSTANCE = new Foo();
68+
}
69+
}
70+
}
71+
return INSTANCE;
72+
}
73+
}
74+
```
75+
76+
上述代码运用了 [Double-Checked Locking idiom](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
77+
78+
解决了多线程环境下的单例,可以进一步思考如何实现可序列化的单例 ? 反序列化可以不通过构造函数直接生成一个对象,所以反序列化时,我们需要保证其不再创建新的对象。
79+
80+
```
81+
class Foo implements Serializable {
82+
83+
private static final long serialVersionUID = 1L;
84+
85+
private static volatile Foo INSTANCE = null;
86+
87+
private Foo() {
88+
if (INSTANCE != null) {
89+
throw new IllegalStateException("Already instantiated");
90+
}
91+
}
92+
93+
public static Foo getInstance() {
94+
if (INSTANCE == null) { // Check 1
95+
synchronized (Foo.class) {
96+
if (INSTANCE == null) { // Check 2
97+
INSTANCE = new Foo();
98+
}
99+
}
100+
}
101+
return INSTANCE;
102+
}
103+
104+
@SuppressWarnings("unused")
105+
private Foo readResolve() {
106+
return INSTANCE;
107+
}
108+
}
109+
```
110+
111+
readResolve 方法可以保证,即使程序在上一次运行时序列化过此单例,也只会返回全局唯一的单例。对于 Java 对象序列化机制,可参考[附录拓展](#appendix)
112+
113+
java 创建单例的方法基本实现了,不过我们还可以作进一步的改进 —— 代码重构:
114+
```
115+
public final class Foo implements Serializable {
116+
117+
private static final long serialVersionUID = 1L;
118+
119+
// 使用内部静态 class 实现懒加载
120+
private static class FooLoader {
121+
// 保证在多线程环境下无差错运行
122+
private static final Foo INSTANCE = new Foo();
123+
}
124+
125+
private Foo() {
126+
if (INSTANCE != null) {
127+
throw new IllegalStateException("Already instantiated");
128+
}
129+
}
130+
131+
public static Foo getInstance() {
132+
return FooLoader.INSTANCE;
133+
}
134+
135+
@SuppressWarnings("unused")
136+
private Foo readResolve() {
137+
return FooLoader.INSTANCE;
138+
}
139+
}
140+
141+
好了,现在已经很完美实现了单例的创建,是不是很高兴。单例实线的基本原理,我们已经基本清楚里,最后提供一种更加简洁方法,如下:
142+
```
143+
public enum Foo {
144+
INSTANCE;
145+
}
146+
```
147+
148+
为什么可以这么简洁?因为 Java 中每一个枚举类型都默认继承了 java.lang.Enum ,而 Enum 实现了 Serializable 接口,所以枚举类型对象都是默认可以被序列化的。通过反编译,也可以知道枚举常量本质上就是一个
149+
```
150+
public static final xxx
151+
````
152+
153+
154+
155+
对于枚举的进一步理解,请参考[附录拓展](#appendix)。
156+
157+
<a id="appendix" name="appendix" />
158+
附录拓展:
159+
[深入理解 Java 对象序列化](http://developer.51cto.com/art/201202/317181.htm)
160+
[对象的序列化和反序列化](http://www.blogjava.net/lingy/archive/2008/10/10/233630.html)
161+
[通过反编译字节码来理解 Java 枚举](http://unmi.cc/understand-java-enum-with-bytecode/)
162+
163+
stackoverflow原址:http://stackoverflow.com/questions/70689/what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java
164+

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.