浅谈设计模式-单例模式

最近一段时间都没有写博客,感觉自己变懒了,这几天反省了一下,决定写点什么,想了想,准备写一下自己对于设计模式的理解。设计模式的思想对于代码的解耦和灵活性有很大的帮助,尤其是项目做的越来越大的时候,合理的使用设计模式的思想来进行代码结构的设计有利于以后的的扩展和维护。

谈到设计模式,大家肯定最先想到的是单例,毕竟大多数人学习设计模式最先接触的就是单例模式。在平时的软件设计中,单例也占据很重要的地位,例如一个APP中用户个人信息就可以使用单例来进行维护等等。接下来就说说我对于单例的理解。

单例的实现方式有很多种,个人看来,不管怎么变,都离不开以下四种方式。

饿汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 饿汉模式
*
* @author Administrator
*
*/
public class Singleton_3 {
private static final Singleton_3 singleton = new Singleton_3();
private Singleton_3() {
};
public static Singleton_3 getInstance() {
return singleton;
}
}

饿汉式简单易懂,不过在类初始化的时候就会被实例化,但可能此时并没有用到它,比较浪费内存。

饱汉式(双重校验锁)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 饱汉模式
*
* @author Administrator
*
*/
public class Singleton_4 {
private static volatile Singleton_4 singleton;
private Singleton_4() {
};
public static Singleton_4 getInstance() {
if (singleton == null) {
synchronized (Singleton_4.class) {
if (singleton == null) {
singleton = new Singleton_4();
}
}
}
return singleton;
}
}

饱汉式实现了lazyload,但是考虑到线程安全和效率问题还是要使用双重校验锁来实现。注意这里单例要加上volatile关键字,否则可能会造成双重校验锁失效问题。

静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 静态内部类模式
*
* @author Administrator
*
*/
public class Singleton_1 {
private Singleton_1() {
};
private static class SingletonHolder {
private static final Singleton_1 singleton = new Singleton_1();
}
public static final Singleton_1 getInstance() {
return SingletonHolder.singleton;
}
}

静态内部类也实现了lazyload,不过它的优点在于避免了线程锁的校验,效率比较高,综合来看,比前两种方式都要好。

枚举

1
2
3
4
5
6
7
8
9
10
11
/**
* 枚举实现
*
* @author Administrator
*
*/
public enum Singleton_2 {
INSTANCE;
public void whatEverYouWant() {
}
}

枚举实现单例应该是最简单的了吧,而且枚举实现的单例无法被破坏,个人感觉实现单例的最佳方式。

问题和对策

前三种方法通过反射、序列化和克隆均可以破坏其单例性,具体破坏代码的实现就不再赘述,大家可以自己试一试,这里只针对这几种破坏单例的方式给出对策。就拿第一种单例实现方式来举例吧。
避免单例被反射破坏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton_3 {
private static boolean flag = false;
private static final Singleton_3 singleton = new Singleton_3();
private Singleton_3() {
synchronized (Singleton_3.class) {//加锁是为了防止多个线程同时利用反射进行实例的创建时产生的问题
if (!flag) {
flag = true;
} else {
throw new RuntimeException("单例模式被破坏...");//利用反射创建实例的时候直接抛出异常
}
}
};
public static Singleton_3 getInstance() {
return singleton;
}
}

避免单例被序列化破坏:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton_3 implements Serializable{
private static final Singleton_3 singleton = new Singleton_3();
private Singleton_3() {
};
public static Singleton_3 getInstance() {
return singleton;
}
private Object readResolve() {
return singleton;//在其反序列化的时候直接返回已存在的单例
}
}

避免单例被克隆破坏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton_3 implements Cloneable{
private static final Singleton_3 singleton = new Singleton_3();
private Singleton_3() {
};
public static Singleton_3 getInstance() {
return singleton;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return singleton;//覆写clone()方法,直接返回已存在的单例
}
}

关于单例,就说这么多吧。

文章目录
  1. 1. 饿汉式
  2. 2. 饱汉式(双重校验锁)
  3. 3. 静态内部类
  4. 4. 枚举
  5. 5. 问题和对策
|