单例模式
2020-10-03 / Lampkins   

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

要点:

  • 构造器私有化
  • 必须自行创建实例,含有一个该类的静态变量来保存这个唯一实例
  • 自行向外部提供改实例

实现方式:

1. 饿汉式:直接创建对象,不存在线程安全问题,但浪费空间

  • 直接实例化饿汉式、枚举式、静态代码块饿汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 饿汉式:直接创建实例对象,不管你是否需要这个对象都会创建
*/
class Singleton1 {
private static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() {}
public static Singleton1 getInstance() {
return INSTANCE;
}
}

/**
* 枚举型
*/
enum Singleton2 {
INSTANCE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 静态代码块方式:可用于初始化参数
*/
class Singleton3 {
private static final Singleton3 INSTANCE;
private String info;
static {
Properties properties = new Properties();
try {
properties.load(Singleton3.class.getClassLoader().getResourceAsStream("singleton.properties"));
} catch (IOException e) {
e.printStackTrace();
}
INSTANCE = new Singleton3(properties.getProperty("info"));
}
private Singleton3(String info) {
this.info = info;
}
public static Singleton3 getInstance() {
return INSTANCE;
}
}

2. 懒汉式:延迟创建对象

  • 线程不安全、线程安全、静态内部类
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
/**
* 懒汉式,线程不安全
*/
class Singleton4 {
private static Singleton4 instance;
private Singleton4() {}
public static Singleton4 getInstance() {
if (instance == null) {
try {
TimeUnit.SECONDS.sleep(1); // 休眠1s以便验证线程不安全
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton4();
}
return instance;
}
public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newFixedThreadPool(5);
Future<Singleton4> f1 = service.submit(Singleton4::getInstance);
Future<Singleton4> f2 = service.submit(Singleton4::getInstance);
Future<Singleton4> f3 = service.submit(Singleton4::getInstance);
System.out.println(f1.get() == f2.get());
System.out.println(f2.get() == f3.get());
service.shutdown();
}
}

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
/**
* 懒汉式,线程安全,双检锁机制(DCL Double Check Lock)
*/
class Singleton5 {
private static volatile Singleton5 instance;
private Singleton5() {}
public static Singleton5 getInstance() {
if (instance == null) {
synchronized (Singleton5.class) {
if (instance == null) {
/*
* 由于编译器的优化、JVM的优化、操作系统处理器的优化,可能会导致指令重排(happen-before规则下的指令重排,执行结果不变,指令顺序优化排列)
* new Singleton5()这条语句大致会有这三个步骤:
* memory = allocate(); //1.在堆中开辟对象所需空间,分配内存地址
* instance(memory); //2.根据类加载的初始化顺序进行初始化
* instance = memory; //3.将内存地址返回给栈中的引用变量
*
* 由于指令重排,可能导致3的顺序和2调换,即类还未初始化完成,但变量已经有了引用地址,故需要用volatile修饰
*/
instance = new Singleton5();
}
}
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 静态内部类:在内部类被初始化时才创建实例对象
*/
class Singleton6 {
public Singleton6() {}
private static class Inner {
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance() {
return Inner.INSTANCE;
}
}
本文链接:
http://lampkins.gitee.io/2020/10/03/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/