什么是单例模式

单例模式(Single Pattern),被单例的对象只能有一个实例存在。单例模式的实现方式是,一个类只能返回对象的一个引用和一个获得该唯一实例的方法(此方法必须是静态方法)。

为什么要使用单例设计模式

通过单例模式,可以保证系统中只有一个实例,从而在某些特定的场合下达到节约或者控制系统资源

单例模式分类及其代码实现

1.饿汉模式

一开始就创建一个实例。虽然较为简单和常见。但有一个明显的缺点,就是不管有没有调用过获得实例的方法,都会创建一个实例。

1
2
3
4
5
6
7
8
 
public class Single {
private static final Single single = new Single();
private Single(){}
public static Single getSingle(){
return single;
}
}
2.懒汉模式

他改进了上述”饿汉模式”的不足之处,调用getSingle() 方法时首先判断实例是否为空,为空才创建实例,并且是调用方法时才创建

1
2
3
4
5
6
7
8
9
10
11
12
13
 

public class Single {
private static Single single;
private Single(){}
public static Single getSingle(){
if (single == null){
single = new Single();
}
return single;
}
}

3.线程安全的懒汉模式

懒汉模式也存在问题。那就是如果有多个线程并行调用getSingle() 方法的时候,还是会创建多个实例,那单例子模式就失效了。所以在此基础上设置线程同步(关键子synchonized)。synchronized的作用就是保证在同一时刻最多只有一个线程运行,这样就避免了多线程带来的问题 。

1
2
3
4
5
6
7
8
9
10
11
 
public class Single {
private static Single single;
private Single(){}
public static synchronized Single getSingle(){
if (single == null){
single = new Single();
}
return single;
}
}
4.双重检验锁

上述解决方法,也不是完美的。每次调用getSingle()时都要进行线程同步,考虑一下这种情况,single对象已经创建了,本来直接返回对象使用即可,但却又要进行线程同步。
于是在此基础之上,又有了双重检验锁的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
public class Single {
private volatile static Single single;
private Single(){}
public static Single getSingle(){
if (single == null){
synchronized (Single.class){
if(single == null){
single = new Single();
}
}
}
return single;
}
}

  • 注意

还需要给实例加一个 volatile 关键字,它的作用就是防止编译器自行优化代码,以保证代码的运行顺序是固定不变的。这涉及到JVM的代码优化机制。

5.静态内部类

上述方法不断改进,有点复杂,其实完全可以通过静态内部类来保证线程安全。

1
2
3
4
5
6
7
8
9
10
11
 

public class Single {
private static class SingleHoder{
private static final Single single = new Single();
}
private Single(){}
public static Single getSingle(){
return SingleHoder.single;
}
}

Single类*是私有的,除getSingle()方法**之外没有其他方式可以访问到实例,而且只有调用改方法时才会去创建实例对象。

6.枚举

这种方法最为简单。我们可以通过Single.INSANCE来访问实例,并且创建枚举默认就是线程安全的,还可以防止反序列化带来的问题。

1
2
3
4
5
 
public enum Single {
INSTANCE;
public void whateverMethod(){};
}

投喂我

写文不易,如果本文对你有帮助,点击Donate,微信和支付宝投喂我