总述
单例,就是单个实例的意思,一般用于只需要一个实例的场景
典型的例子就是各种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(){};
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; }
|