概要:主要有以下五种,除了4和5 ,安全与否取决于是否加synchronized关键字,加了之后肯定对效率肯定有影响
- 懒汉
- 饿汉
- 二次检查
静态内部类(只加载一次)
以上四种都存在2个问题
- 会被反射的setAccessible(true)破坏单例模式;
- 反序列化时会破坏单例
解决方式如下:
单元素枚举(最优)
//懒汉
class LazySingleton{
private static LazySingleton singLeton = new LazySingleton();
private LazySingleton(){
}
public synchronized LazySingleton getLazySingleton(){
if(singLeton==null){
return new LazySingleton();
}
return singLeton;
}
}
//饿汉
class HunSingleton{
//安全,但类加载时就初始化
private static HunSingleton singleton = new HunSingleton();
private HunSingleton(){}
public static HunSingleton getHunSinglelton(){
return singleton;
}
}
//双重校验
class DoubleCheckSingleton{
private static DoubleCheckSingleton singleton;
private DoubleCheckSingleton(){}
public static DoubleCheckSingleton getHunSinglelton(){
if(singleton==null){
synchronized(DoubleCheckSingleton.class){
//第二次判断的目的是在第一次判断的时候创建了对象
//第一次判断是为了效率
if(singleton==null){
return new DoubleCheckSingleton();
}
}
}
return singleton;
}
}
//静态内部类
class ClazzSingleton{
private ClazzSingleton(){};
public ClazzSingleton getSingleton(){
return InnerClazz.singleton;
}
static class InnerClazz{
private static ClazzSingleton singleton = new ClazzSingleton();
}
//用于解决反序列化后 对象不一致的问题,直接在类里加一下方法:
private Object readResolve(){
return singleton;
}
//解决被反射破坏单例的问题:在构造函数中增加次数验证,类似于List中的madCount
private Demo() throws Exception{
if(madCount!=0){
throw new Exception("创建过对象");
}
madCount++;
}
//单元素枚举
enum EnumSingleton{
INSTANCE;
public void show(){
System.out.println("Ea");
}
}
//利用反射破坏单例模式
public void destroy(){
try {
Constructor<Demo> coo = Demo.class.getDeclaredConstructor();
//此处设置权限
coo.setAccessible(true);
Demo d = coo.newInstance();
Demo e = coo.newInstance();
System.out.println(d==e);//false
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}