发布于 

设计模式-单例模式(Singleton Pattern)

  单例模式通俗的解释就是一个类只有唯一的对象实例,那要怎么才能实现这一点呢?首先要知道所以的单例模式都是用静态方式实现的,单例对象实例都是存储在静态共享区。好了,知道了这些,下面就介绍具体是怎么实现的。

实现方法

  一般要做这三件事!
  1、构造函数私有化(防止使用 new() 方法创建出多个对象实例)
  2、进行初始化生成一个静态的对象实例(在不同时间生成,就产生了不同的写法)
  3、提供 getInstance() 方法,返回一个生成的那个对象实例(方法名可以自己定义,只是习惯写成 getInstance)

常见类型

  第一种:饿汉式(在类加载时就完成了初始化)
  第二种:懒汉式(在类加载时不初始化而是在 getInstance() 方法中判断对象是否为 null,为空才初始化)
  第三种:静态内部类(在静态内部类中,初始化对象实例)

代码实现

1、饿汉式(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package test;
/**
* 饿汉式
* 线程是安全的
*/
public class SingleInstance {
//在类加载时就完成了初始化,final使对象实例不能改变(可写可不写,推荐写,javaApi里的单例也用了这个关键字)
//final(保证对象的安全发布,防止对象引用被其他线程在对象被完全构造完成前拿到并使用)
private static final SingleInstance INSTANCE = new SingleInstance();
private SingleInstance() {} //构造函数私有化

private static SingleInstance getInstance() { //获取对象的方法
return INSTANCE;
}

public static void main(String[] args) {
SingleInstance test1 = SingleInstance.getInstance();
SingleInstance test2 = SingleInstance.getInstance();
System.out.println(test1 == test2);
}
}

2、懒汉式(不推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package test;
/**
* 懒汉式
* 线程不安全型
*/
public class SingleInstance {
//在类加载时,只进行声明,不进行初始化,不能写final,因为后面要赋值修改
private static SingleInstance INSTANCE;
private SingleInstance() {} //构造函数私有化

private static SingleInstance getInstance() { //获取对象的方法
if(INSTANCE == null) {
INSTANCE = new SingleInstance();
}
return INSTANCE;
}

public static void main(String[] args) {
SingleInstance test1 = SingleInstance.getInstance();
SingleInstance test2 = SingleInstance.getInstance();
System.out.println(test1 == test2);
}
}

  上面写法在多线程需要同步的环境下不能正常工作,那把它改为线程安全型的。
  改为线程安全型的懒汉式,只需要在 getInstance() 方法前加上同步锁关键字 synchronized 即可,但加了同步锁之后,效率会变得很低,毕竟大多数情况下不需要同步的。所以推荐大家使用第一种方式。

3、静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package test;
/**
* 静态内部类
* 资源利用率高
*/
public class SingleInstance {
//在静态内部类中,初始化对象实例,相比饿汉式,不执行getInstance()就不会被实例,节省资源
private static class SingletonHelp{
static final SingleInstance instance = new SingleInstance();
}

private SingleInstance() {} //构造函数私有化

private static SingleInstance getInstance() { //获取对象的方法
return SingletonHelp.instance;
}

public static void main(String[] args) {
SingleInstance test1 = SingleInstance.getInstance();
SingleInstance test2 = SingleInstance.getInstance();
System.out.println(test1 == test2);
}
}

总结

  对象的创建比较消耗资源,只需要一个时,比如资源共享的情况下,就可以使用单例模式,这样可以避免由于资源操作时导致的性能或损耗等。
  再次说明,一般采用饿汉式,如果对资源要求利用率高,可以采用静态内部类,不建议采用懒汉式。