总述

单例,就是单个实例的意思,一般用于只需要一个实例的场景
典型的例子就是各种Mgr,以及游戏的角色操控

写法

一般来说,单例模式有七种写法,下面一一列出

1饿汉

类加载到内存后,就实例化一个单例,此时JVM会保证线程安全
简单实用,实用性强
唯一确定是不管是否被用到,在装载类的时候就会完成实例化

但是如果你不用它,你装载啥啊

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();

private Mgr01(){}; //这里的private保证了它不会被随随便便NEW出来

//设置一个getInstance方法,想要得到它只能使用这个方法

public static Mgr01 getInstance(){
return INSTANCE ;
}


}

2饿汉改

和第一个本质上没区别

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Mgr02{
private static final Mgr02 INSTANCE ;

static{
INSATNCE = new Mgr02();
}

private Mgr02() { };

public static Mgr02 getInstance(){
return INSTANCE ;
}
}

3懒汉式

什么时候使用,就在什么时候初始化
缺点在于带来了多线程访问时的影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Mgr03 {
private static Mgr03 INSTANCE ;

private Mgr03(){

}

public static Mgr03 getInstance(){
if(INSTANCE == null){
INSTANCE = new Mgr03();
}

return INSTANCE ;
}

//有需要,之前没初始化过,就得到它,否则就直接返回

}

4加锁懒汉式

既然之前说多线程访问有影响,那么就加锁
这样下去,虽然可以通过synchronized解决,但是相应的,效率降低了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Mgr04 {
private static Mgr04 INSTANCE ;

private Mgr04(){

}

public static synchronized Mgr04 getInstance(){
if(INSTANCE == null){
INSTANCE = new Mgr04();
}

return INSTANCE ;
}

//有需要,之前没初始化过,就得到它,否则就直接返回

}

5双重检查单例写法

完美的方法之一,利用两次检查保证安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Mgr05 {
private static volatile Mgr05 INSTANCE ;

private Mgr05(){

}

public static Mgr05 getInstance(){
if(INSTANCE == null){

synchronized(Mgr05.class){
if(INSTANCE == null){
INSTANCE = new Mgr05();
}
}
}

return INSTANCE ;
}

//有需要,之前没初始化过,就得到它,否则就直接返回

}

6静态内部类写法

JVM保证单例
加载外部类的时候不会加载内部类,这样可以实现懒加载
完美的方法之二,而且简单好写

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Mgr06{
private Mgr06(){

}

private static class Mgr06Holder {
private final static Mgr06 INSTANCE = new Mgr07() ;
}

public static Mgr06 getInstance() {
return Mgr06Holder.INSTANCE ;
}
}

7ENUM

完美的方法其三
不仅解决了线程同步,还可以防止反序列化
EffectiveJava中的写法

1
2
3
public enum Mgr07{
INSTANCE;
}