单例模式

单例模式

单例模式:一个类只能有一个实例化对象,多个线程共享该实例对象的资源;要求:

  1. 外部不能随意调用构造函数创建对象;

    私有化构造器

  2. 内部对外提供一个可调用的 public 函数,通过该函数获取单例对象;

    这个方法要定义为 static,因为构造函数为私有,外部不能通过创建实例对象来调用该方法,只能定义为静态,通过类调用

最基本思想,单线程下实现单例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingletonDemo {

private static SingletonDemo singletonDemo = null;

private SingletonDemo() {
System.out.println("创建了SingletonDemo对象");
}

public static SingletonDemo getInstance() {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
return singletonDemo;
}
}

多线程下,对 public 方法加锁,使同一时间只有一个线程能访问该资源:

1
2
3
4
5
6
public synchronized static SingletonDemo getInstance() {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
return singletonDemo;
}

也可以锁定其他共享资源,如代码块、类等;更推荐锁代码块,因为影响同步的代码可能不是整个方法,更细粒度的锁灵活性较高。

1
2
3
4
5
6
7
8
public static SingletonDemo getInstance() {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
return singletonDemo;
}

注:应先锁,再判空;先判空,会有多个线程进入创建对象的代码块等待资源。

更加安全,使用 double check,双重校验锁:

1
2
3
4
5
6
7
8
9
10
public static SingletonDemo getInstance() {
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
}
return singletonDemo;
}

绝对安全,定义对象时加上 volatile 关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SingletonDemo {

private volatile static SingletonDemo singletonDemo = null;

private SingletonDemo() {
System.out.println("创建了SingletonDemo对象");
}

public static SingletonDemo getInstance() {
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
}
return singletonDemo;
}
}

volatile 的作用:使内存中的数据对线程可见

一个线程在访问内存数据时,拿到的不是数据本身,而是将主内存中的东西复制保存在工作内存,相当于对内存中数据的副本进行操作,操作完成后再将数据保存到主内存;即主内存对线程是不可见的


单例模式
http://example.com/2022/08/07/单例模式/
作者
fkxia
发布于
2022年8月7日
许可协议