设计模式:单例模式

声明:本文仅限用于学术交流,引用或转载本文时请注明出处!

单例模式保证一个类仅有一个实例,并提供一个访问他的全局函数。当系统开发中某个类只能有一个实例时,就可以采用单例模式。

单例模式

单例模式是一种常用的软件设计模式。在他的核心 结构中只包含一个被称为单例的特殊类,保证系统中该类只有一个实例。
总之,单例模式具有以下特点:

  1. 单例类只能有一个实例
  2. 单例类必须自己创建自己唯一的实例
  3. 单例类必须给所有的其他对象都能提供这一实例。
    保证单例模式仅有一个实例的核心思想是构造方法私有化,所以单例模式的方法主要有以下两种。

直接实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @author William Mou
* @date 2019/4/27 18:53
* 直接生成实例
*/
public class Singleton1 {
private static final Singleton1 SINGLETON_1 = new Singleton1();
//避免外部调用
private Singleton1() {
System.out.println("初始化单例模式");
}
//返回单例对象的实例
public static Singleton1 getInstance() {
return SINGLETON_1;
}
}

延迟实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @author William Mou
* @date 2019/4/27 18:58
* 延迟实例化
*/
public class Singleton2 {
private static volatile Singleton2 singleton2 = null;

private Singleton2() {
System.out.println("初始化实例");
}

// 方法一:单线程
public static Singleton2 getInstance1() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}

与直接实例化不同,单例成员变量singleton2首先初始化为null,它在方法getInstance()内完成延迟实例化,并返回单例对象,但是该方法存在线程安全问题。如果两个线程都在执行getInstance()方法,线程一已经在执行if (singleton2 == null)后,在执行完singleton2 = new Singleton2()前,线程二正在执行if (singleton2 == null)也成立,这样将会生成两个单例对象,违背了单例模式。

线程安全-synchronized完全同步方法

1
2
3
4
5
6
public static synchronized Singleton2 getInstance2() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}

使用synchronized关键字后,当多线程同时访问getInstance()方法的时候,多线程将穿行运行。

线程安全-synchronized部分同步方法

1
2
3
4
5
6
7
8
9
10
11
// 方法三:多线程synchronized代码块
public static Singleton2 getInstance3() {
if (singleton2 == null) {
synchronized (Singleton2.class){
if (singleton2 == null){ //再次确认对象是否实例化
singleton2 = new Singleton2();
}
}
}
return singleton2;
}

此方法中,只有当对象还没实例化的时候会串行执行,其他的时候可并行运行。与完全同步方法相比,提高了运行效率。

线程安全-静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @author William Mou
* @date 2019/4/27 19:08
* 静态内部类
*/
public class Singleton3 {
private Singleton3(){
System.out.println("实例初始化");
}
private static class My{
private static final Singleton3 SINGLETON_3 = new Singleton3();
}
public static Singleton3 getInstance(){
return My.SINGLETON_3;
}
}

与使用synchronized关键字的方法相比,此方法提高了Java虚拟机的维护效率,而且此方法还是线程安全的。

参考文献

wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器