设计模式之七种单例模式

对其中单例模式做个总结,以备不时之需。

饿汉单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package singleton;
/**
* Created by cdx0312
* 2018/3/23
* 饿汉,基于ClassLoader机制避免了多线程的同步问题,加载过程较慢,获取对象速度较快
* 不过instance在类装载时就实例化。虽然大多数情况下调用单例模式的getInstance方法导致类加载,但是也不能确定没有其他
* 静态方法导致类被加载,从而没有达到懒加载的效果。
*/
public class Singleton {
private Singleton() {
}
private static Singleton singleton = new Singleton();
public static Singleton getInstance() {
return singleton;
}
}

懒汉(线程不安全)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package singleton;
/**
* Created by cdx0312
* 2018/3/24
* 懒汉设计模式,线程安全,但是效率很低,每次调用getInstance方法都需要
* 获得锁,而大多数情况下不需要同步
*/
public class Singleton1 {
private Singleton1(){
}
private static Singleton1 singleton1;
public static synchronized Singleton1 getInstacne(){
if (singleton1 == null)
singleton1 = new Singleton1();
return singleton1;
}
}

懒汉(线程安全)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package singleton;
/**
* Created by cdx0312
* 2018/3/24
* 懒汉设计模式,线程不安全
*/
public class Singleton2 {
private Singleton2(){
}
private static Singleton2 singleton1;
public static Singleton2 getInstacne(){
if (singleton1 == null)
singleton1 = new Singleton2();
return singleton1;
}
}

双重检查单例模式

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
package singleton;
/**
* Created by cdx0312
* 2018/3/30
* 双重检查模式,第一次是为了减少不必要的同步,当singleton对象存在时,
* 直接返回实例对象,则同步只发生在多个线程同时调用getInstance加载类
* 第二次判空是为了singleton为null才创建实例。
* DCL优点是资源利用率高,第一次执行getInstance时单例对象才被实例化,效率高。
* 缺点是第一次加载速度慢,高并发场景中也会影响其性能,但是也存在DCL失效,
* 建议使用静态内部类单例模式来替代DCL
*/
public class Singleton3 {
private volatile static Singleton3 singleton;
private Singleton3() {
}
public static Singleton3 getInstance() {
if (singleton == null) {
synchronized (Singleton3.class) {
if (singleton == null) {
singleton = new Singleton3();
}
}
}
return singleton;
}
}

静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package singleton;
/**
* Created by cdx0312
* 2018/3/30
* 静态内部类单例:
* 第一次加载Singleton类时并不会初始化是Instance,只有第一次调用Singleton
* 方法时虚拟机加载SingletonHolder并初始化sInstance,这样不仅能确保线程安
* 全也能保证Singleton的唯一性,推荐使用。
*/
public class Singleton4 {
private Singleton4() {
}
public static Singleton4 getInstance() {
return SingletonHolder.sInstance;
}
private static class SingletonHolder{
private static final Singleton4 sInstance = new Singleton4();
}
}

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package singleton;
/**
* Created by cdx0312
* 2018/3/30
* 默认枚举类实例的创建是线程安全的,并且在任何情况下都是单例,上述的几种
* 单例在反序列化的情况下会创建对象,将一个单例实例对象写到磁盘再读回来,
* 从而获得一个实例。反序列化操作提供了
*/
public enum Singleton5 {
INSTANCE;
public void doSomething() {
}
}

容器实现单例

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
package singleton;
import java.util.HashMap;
import java.util.Map;
/**
* Created by cdx0312
* 2018/3/30
* 使用容器实现单例模式
* 用SingletonManager 将多种的单例类统一管理,在使用时根据key获取对象
* 对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用
* 时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐
* 藏了具体实现,降低了耦合度。
*/
public class Singleton6 {
private static Map<String, Object> objectMap = new HashMap<>();
private Singleton6() {
}
public static void registerService(String key, Object instance) {
if (!objectMap.containsKey(key)) {
objectMap.put(key, instance);
}
}
public static Object getService(String key) {
return objectMap.get(key);
}
}
Donate comment here