单例模式

单例模式

1. 简介

2. 常见的五种单例模式

2.1 饿汉式

使用前提:方法中不需要开辟更多空间

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
//饿汉式单例模式

public class SingletonDemo01 {
//1.私有化构造器
private SingletonDemo01(){

}

//2.类初始化的时候就,立即加载该对象
private static SingletonDemo01 instance = new SingletonDemo01();

//3.提供获取该对象的方法,没有synchronized,效率高!
public static SingletonDemo01 getInstance(){
return instance;
}
}

// 测试是否成功
class SingletonDemo01test{
public static void main(String[] args) {
// SingletonDemo01 singletonDemo01 = new SingletonDemo01();//不能new
SingletonDemo01 instance = SingletonDemo01.getInstance();
SingletonDemo01 instance2 = SingletonDemo01.getInstance();
System.out.println(instance==instance2); //true 确保拿到的是一个对象
}
}

2.2 懒汉式

可以实现延迟加载:

synchronized:如果有多个线程同时进来,需要排队处理

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
29
//懒汉式
public class SingletonDemo02 {
//1.私有化构造器
private SingletonDemo02(){

}

//2.类初始化的时候就,不立即加载该对象
private static SingletonDemo02 instance;

//3.提供获取该对象的方法,有synchronized,效率低!
public static synchronized SingletonDemo02 getInstance(){
if (instance == null){
instance = new SingletonDemo02();
}
return instance;
}
}


//测试是否成功
class SingletonDemo02test{
public static void main(String[] args) {
// SingletonDemo02 singletonDemo02 = new SingletonDemo02();//不能new
SingletonDemo02 instance = SingletonDemo02.getInstance();
SingletonDemo02 instance2 = SingletonDemo02.getInstance();
System.out.println(instance==instance2); //true 确保拿到的是一个对象
}
}

2.3 DCL懒汉式

volatile作用:避免指令的重排,保证原子性

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
29
30
31
32
33
34
35
36
37
//DCL懒汉式
public class SingletonDemo03 {
//1.私有化构造器
private SingletonDemo03(){

}

//2.类初始化的时候就,不立即加载该对象
//volatile作用:避免指令的重排,保证原子性
private volatile static SingletonDemo03 instance;

//3.提供获取该对象的方法,有synchronized,效率低!
public static SingletonDemo03 getInstance(){
if (instance == null){
synchronized (SingletonDemo03.class){
if (instance==null){
instance = new SingletonDemo03();
}
}
}
return instance;
}

//1. 分配内存
//2. 执行构造方法
//3. 指向地址
}

//测试是否成功
class SingletonDemo03test{
public static void main(String[] args) {
// SingletonDemo03 singletonDemo03 = new SingletonDemo03();//不能new
SingletonDemo03 instance = SingletonDemo03.getInstance();
SingletonDemo03 instance2 = SingletonDemo03.getInstance();
System.out.println(instance==instance2); //true 确保拿到的是一个对象
}
}

2.4 饿汉式改进:静态内部类实现

前四种中最优秀的

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//饿汉式改进:静态内部类实现
public class SingletonDemo04 {
//1.私有化构造器
private SingletonDemo04() {

}

//2.不会一出生就加载
private static class InnerClass {
//final:保证线程中只有一个存在
private static final SingletonDemo04 instance = new SingletonDemo04();
}

//3.只有调用的时候才会加载
public static SingletonDemo04 getInstance() {
return InnerClass.instance;
}

}

//反射机制会破坏这个机制

//测试是否成功
class SingletonDemo04test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
SingletonDemo04 instance = SingletonDemo04.getInstance();
SingletonDemo04 instance2 = SingletonDemo04.getInstance();
System.out.println(instance==instance2); //true 确保拿到的是一个对象

//反射机制会破坏这个机制
Constructor<SingletonDemo04> declaredConstructor = SingletonDemo04.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true); //关闭private权限
SingletonDemo04 instance3 = declaredConstructor.newInstance();
System.out.println(instance==instance3);
System.out.println(instance.hashCode());
System.out.println(instance3.hashCode());

}
}

2.5 枚举单例

纯天然防止反射破坏(弊端:不能延迟加载)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//枚举单例模式
public enum SingletonDemo05 {

INSTANCE; //纯天然单例模式

public SingletonDemo05 getInstance(){
return INSTANCE;
}
}


//测试

class SingletonDemo05Test{
public static void main(String[] args) {
SingletonDemo05 instance = SingletonDemo05.INSTANCE;
SingletonDemo05 instance2 = SingletonDemo05.INSTANCE;
System.out.println(instance==instance2);
}
}

3. 防止反射破坏单例模式

3.1 防止一次反射破坏单例模式

  1. 在私有化构造器中添加操作
1
2
3
4
5
6
7
8
9
10
//DCL懒汉式
public class SingletonDemo03 {
//1.私有化构造器
private SingletonDemo03(){
synchronized (SingletonDemo03.class){
if (instance!=null){
throw new RuntimeException("不要试图用反射破坏单例");
}
}
}

全部测试代码如下:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//DCL懒汉式
public class SingletonDemo03 {
//1.私有化构造器
private SingletonDemo03(){
synchronized (SingletonDemo03.class){
if (instance!=null){ //假设已经存在instance了,不能再new
throw new RuntimeException("不要试图用反射破坏单例");
}
}
}

//2.类初始化的时候就,不立即加载该对象
//volatile作用:避免指令的重排
private volatile static SingletonDemo03 instance;

//3.提供获取该对象的方法,有synchronized,效率低!
public static SingletonDemo03 getInstance(){
if (instance == null){
synchronized (SingletonDemo03.class){
if (instance==null){
instance = new SingletonDemo03();
}
}
}
return instance;
}

//1. 分配内存
//2. 执行构造方法
//3. 指向地址
}

//测试反射破坏是否成功
class SingletonDemo03test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
SingletonDemo03 instance = SingletonDemo03.getInstance();
SingletonDemo03 instance2 = SingletonDemo03.getInstance();
System.out.println(instance==instance2); //true 确保拿到的是一个对象

//测试反射破坏是否成功
Constructor<SingletonDemo03> declaredConstructor = SingletonDemo03.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
SingletonDemo03 instance3 = declaredConstructor.newInstance();
System.out.println(instance==instance3);
System.out.println(instance.hashCode());
System.out.println(instance3.hashCode());

}
}

3.2 防止两次反射破坏单例模式

通过标志位防止两次反射创建对象破坏单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
//通过标志位防止两次反射创建对象破坏单例模式
private static boolean flag = false;

//1.私有化构造器
private SingletonDemo03(){
synchronized (SingletonDemo03.class){
if (flag == false){
flag = true;
}else {
throw new RuntimeException("不要试图用反射破坏单例");
}
}
}

3.3 枚举防止破坏反射破坏单例模式

点进newInstance()源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//枚举单例模式
public enum SingletonDemo05 {

INSTANCE; //纯天然单例模式

public SingletonDemo05 getInstance(){
return INSTANCE;
}
}


//测试

class SingletonDemo05Test{
public static void main(String[] args) {
SingletonDemo05 instance = SingletonDemo05.INSTANCE;
SingletonDemo05 instance2 = SingletonDemo05.INSTANCE;
System.out.println(instance==instance2);
}
}
打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信