前言
在windows系统中,我们可以发现无论我们如何去开启任务管理器,都只能打开一个窗口,因为每个窗口显示的数据,做的功能都是一样的。我们日常的编码中,经常会遇到这样的情况,某个类希望只存在一个实例,这就需要用到 单例模式了 。
饿汉式
饿汉式单例模式比较简单。1
2
3
4
5
6
7
8
9
10
11public class Singleton{
private static final Singleton instance = Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
从上面的代码可以看出,在类加载的时候就会创建Singleton的对象。
懒汉式
懒汉式单例模式,就是讲对象的实例化放在使用的时候。1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
上面这串代码在单线程里面是能够保证只创建一个对象的。但是放到多线程里面就会出现创建多个对象的情况。所以我们如果要创建一个线程安全的单例,则需要加 synchronized 关键字。1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Singleton{
private static Singleton instance;
private Singleton(){}
public synchronized static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
但是加上同步之后又出现了另外一个性能问题,如果有很多个线程都在请求这个方法,而且这个方法里面要做很多的初始化操作,就会导致其他线程持续等待等情况,下面不使用方法锁的情况,但是需要加双重校验,因为有可能A线程走完第一层的判断后,CPU执行片给了B线程,然后B线程获取锁创建了对象,如果同步代码块里面不添加一层校验就会导致A线程也会创建对象。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
holder模式
饿汉式没有办法延时加载,而懒汉式的同步在高并发的情况下又会影响性能。那么有没有另外一种方式能够克服这两者的缺点呢?答案肯定是有的。1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return Holder.instance;
}
private static class Holder {
private static final Singleton instance = new Singleton();
}
}
由于静态单例对象没有作为Singleton的成员变量直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()时将加载内部类Holder,在该内部类中定义了一个static类型的变量instance,此时会首先初始化这个成员变量,由Java虚拟机来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。
Kotlin下的单例模式
饿汉式
kotlin下的饿汉式就有意思了,如下就是一个饿汉式的单例模式。1
object Singleton
你没有看错,他就是一个饿汉式,我们通过工具可以看到它对应的java代码如下。1
2
3
4
5
6
7
8
9
10
11public final class Singleton {
public static final Singleton INSTANCE;
private Singleton() {
INSTANCE = (Singleton)this;
}
static {
new Singleton();
}
}
懒汉式
kotlin里面是没有synchronized关键字的,如果要是用同步方法的形式,则需要使用 @Synchronized 注解。而同步代码块的方式是使用 synchronized() 方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Singleton private constructor() {
companion object {
private var instance: Singleton? = null
fun getSingleton(): Singleton {
if (instance == null) {
synchronized(Singleton::class.java) {
if (instance == null) {
instance = Singleton()
}
}
}
return instance!!
}
}
}
holder方式
再来看看holder方式如何通过kotlin来实现。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Singleton private constructor() {
companion object {
fun getSingleton(): Singleton {
return Holder.instance
}
}
private object Holder {
val instance: Singleton = Singleton()
}
}
毒鸡汤
日子还长,别太失望~