很早的时候,转发过一篇单例模式的文章:http://iamzhongyong.iteye.com/blog/1539642
最近又翻了一本设计模式的书,然后发现单例其实也简单也复杂,于是就打算把代码敲一下,保存下来。
------------------------------------------------------------------------------------------------------
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
|
package
singleton;
/**
* 最简单的单例模式
*/
public
class
SimpleSingleton {
/**
* 构造方法私有化,外部无法通过构造方法创建对象,这样能够屏蔽外部直接new
* 还有就是反射了,反射时可以使用setAccessible方法来突破private的限制,
* 我们需要做到第一点工作的同时,还需要在在ReflectPermission("suppressAccessChecks")
* 权限下使用安全管理器(SecurityManager)的checkPermission方法来限制这种突破,
* 一般来说,不会真的去做这些事情,都是通过应用服务器进行后台配置实现。
* 再就是序列化了,序列化会在SimpleSerializableSingleton这个类中做介绍
*/
private
SimpleSingleton(){}
/**
* 类型是static,这样在JVM进行类加载的时候就会做类的实例化,JVM保证线程安全
* 根据JLS(Java Language Specification)中的规定,一个类在一个ClassLoader中只会被初始化一次,
* 这点是JVM本身保证的,那就把初始化实例的事情扔给JVM好了
*/
private
static
final
SimpleSingleton instance =
new
SimpleSingleton();
//通过一个静态方法,获得这个对象
public
static
SimpleSingleton getInstance(){
return
instance;
}
}
|
------------------------------------------------------------------------------------------------------
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
|
package
singleton;
/**
* 单例模式的懒加载策略,不在类加载的时候进行实例化,而是在第一次调用的时候进行
*/
public
class
SimpleLazySingleton {
//私有构造方法
private
SimpleLazySingleton(){}
//在类加载的时候,这个对象不进行实例化,volatile变量,拥有可见性
private
static
volatile
SimpleLazySingleton instance =
null
;
/**
* @deprecated
* 这种会有线程安全问题,因为可能存在多线程访问这个方法,这个时候对象就有可能不是单例的
*/
public
static
SimpleLazySingleton getInstanceNotSafe(){
if
(instance ==
null
){
instance =
new
SimpleLazySingleton();
}
return
instance;
}
/**
* @deprecated
* 做一个简单的处理,就是在getInstance的时候添加锁关键字
* 但是这样有个问题,就是所有的getInstance操作全部加锁,性能会下降很多
*/
public
static
synchronized
SimpleLazySingleton getInstanceSyncSafe(){
if
(instance ==
null
){
instance =
new
SimpleLazySingleton();
}
return
instance;
}
/**
* @deprecated
* 那就做锁的细化吧,把锁的处理挪到方法体内部,仅仅在instance为空的时候,再去加锁
*/
public
static
SimpleLazySingleton getInstanceSyncNotSafe(){
if
(instance ==
null
){
synchronized
(SimpleLazySingleton.
class
) {
instance =
new
SimpleLazySingleton();
}
}
return
instance;
}
/**
* 那就做锁的细化吧,把锁的处理挪到方法体内部,仅仅在instance为空的时候,再去加锁
*/
public
static
SimpleLazySingleton getInstance(){
if
(instance ==
null
){
synchronized
(SimpleLazySingleton.
class
) {
/**
* 这里称之为double-check-lock,为啥要做这不操作呢?
* 因为可能有多个线程进入第一个“if(instance == null)”,这个时候,线程去强占锁,
* 抢到锁的线程进行instance的初始化操作,完了之后释放锁,
* 第二个线程获得锁,这个时候进入之后,如果没有判空操作,会再一次初始化了实例,这时候就不是单例了
*/
if
(instance ==
null
){
instance =
new
SimpleLazySingleton();
}
}
}
return
instance;
}
}
|
------------------------------------------------------------------------------------------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
singleton;
/**
* 通过Holder的形式来进行,利用JVM的机制来保障线程安全
*/
public
class
SimpleHolderSingleton {
//私有化
private
SimpleHolderSingleton(){}
//类中有一个私有的XXXHolder类,这个因为是static类型的,所以在JVM加载类的时候就会加载到,但是INSTANCE就不会
private
static
class
SimpleHolderSingletonHolder{
//持有外部类的属性
static
final
SimpleHolderSingleton INSTANCE =
new
SimpleHolderSingleton();
}
//这样会在第一次调用的时候进行初始化操作,因为INSTANCE是static的,所以借助了JVM的机制来保障线程安全
public
static
SimpleHolderSingleton getInstance(){
return
SimpleHolderSingletonHolder.INSTANCE;
}
}
|
------------------------------------------------------------------------------------------------------
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
|
package
singleton;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileOutputStream;
import
java.io.ObjectInputStream;
import
java.io.ObjectOutputStream;
/**
* 如果单例的类实现了序列化接口,这个时候需要做一下特殊处理,
*/
public
class
SimpleSerializableSingleton
implements
java.io.Serializable{
private
static
final
long
serialVersionUID = -589503673156379879L;
//屏蔽外部new的实例化
private
SimpleSerializableSingleton(){}
private
static
SimpleSerializableSingleton instance =
new
SimpleSerializableSingleton();
public
static
SimpleSerializableSingleton getInstance(){
return
instance;
}
/**
* 这个方法,会在发序列化构建对象的时候调用到,如果不这么处理
* 反序列化之后的对象,是另外一个内存地址,也就是说不再是单例的了
*/
private
Object readResolve() {
System.out.println(
"readResolve,被调用了"
);
return
getInstance();
}
public
static
void
main(String[] args)
throws
Exception {
SimpleSerializableSingleton simple = SimpleSerializableSingleton.getInstance();
//获得单例对象的内存地址
System.out.println(simple);
//定义序列化写入的文件
File file =
new
File(
"d:\\git\\serializable"
);
//构造objectOutputStream
ObjectOutputStream outStream =
new
ObjectOutputStream(
new
FileOutputStream(file));
//写入对象
outStream.writeObject(simple);
outStream.close();
//反序列化
ObjectInputStream inStream =
new
ObjectInputStream(
new
FileInputStream(file));
SimpleSerializableSingleton simpeFromSeria = (SimpleSerializableSingleton)inStream.readObject();
System.out.println(simpeFromSeria);
inStream.close();
}
}
|
------------------------------------------------------------------------------------------------------
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
|
package
singleton;
import
java.lang.reflect.ReflectPermission;
import
java.security.Permission;
/**
* 如何禁止外部通过反射来做单例对象的序列化
*/
public
class
SimpleReflectionSingleton {
private
SimpleReflectionSingleton(){}
private
static
SimpleReflectionSingleton instance =
new
SimpleReflectionSingleton();
public
static
SimpleReflectionSingleton getInstance(){
return
instance;
}
public
static
void
main(String[] args)
throws
Exception{
//启动JVM的安全检察,在进行反射校验的时候,判断一下是否是“singleton”,如果是,就禁止反射
System.setSecurityManager(
new
SecurityManager(){
@Override
public
void
checkPermission(Permission perm) {
if
(perm
instanceof
ReflectPermission &&
"suppressAccessChecks"
.equals(perm.getName())) {
for
(StackTraceElement elem : Thread.currentThread().getStackTrace()) {
if
(elem.getClassName().endsWith(
"Singleton"
)) {
throw
new
SecurityException();
}
}
}
}
});
SimpleReflectionSingleton simple = SimpleReflectionSingleton.getInstance();
System.out.println(simple);
Class<?> clazz = SimpleReflectionSingleton.
class
;
SimpleReflectionSingleton ref = (SimpleReflectionSingleton)clazz.newInstance();
System.out.println(ref);
}
}
|