单例模式
# 单例模式
单例模式有几点是基础要求
- 构造函数私有
- 私有成员变量 (为该类的一个实例)
# 饿汉式,在类初始化时就创建好了单例对象
public class Design {
private Design(){
System.out.println("私有构造方法调用");
}
private static final Design singleton1= new Design();
public static Design get(){
return singleton1;
}
public static void jk(){
System.out.println("kkk");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 懒汉式,只有在调用的时候才创建对象
# 基础版-懒汉式
public class Design2 {
private Design2(){
System.out.println("design2");
}
private static Design2 singleton2 = null;
public static Design2 getInstance(){
if(singleton2==null){
singleton2 = new Design2();
}
return singleton2;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上述实现在多线程情况下是会出现非单例的情况的,即A,B两个线程都判断了singleton2为null,从而new了两个对象,
可以考虑在方法上加 synchronized 来保证单例。但是此方法效率不高,实际上我们只需要在第一次创建的时候加锁即可,之后获取的时候是没有必要加锁的。
public class Design2 { 效率不高,不推荐
private Design2(){
System.out.println("design2");
}
private static Design2 singleton2 = null;
public static synchronized Design2 getInstance(){
if(singleton2==null){
singleton2 = new Design2();
}
return singleton2;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 改进版-双检锁懒汉式
第一次null判断的主要作用在于检查是否已经实例化了对象,有则立马返回
第二次null判断的主要作用在于为了防止多线程情况下可能存在多个线程通过了第一次null判断,而导致的多次创建对象
public class Design3 {
private Design3 (){
System.out.println("Design3构造调用");
}
private static volatile Design3 singleton= null;
public static Design3 getInstance(){
if(singleton == null){
synchronized (Design3.class){
if(singleton == null){ // 此处也判断一下null是为了防止多线程情况下可能存在多个线程通过 //了第一次null判断,而导致的多次创建对象
singleton = new Design3();
}
}
}
return singleton;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# volatile的使用原因
# 推荐使用-内部类懒汉式
public class Design4 {
private Design4 (){
System.out.println("Design4构造调用");
}
private static class Content{
private static Design4 singleton = new Design4();
}
public static Design4 getInstance(){
return Content.singleton;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 原理
想想看,为什么饿汉式不存在多线程情况造成的多实例问题
上次更新: 2024/08/09, 16:07:34