-# 单例模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。 下面便是单例模式的三种实现方式
饿汉式
//饿汉式单例,但是会浪费资源空间
public class Hungry {
//构造器私有化
private Hungry(){
}
//内部创建类的对象(要求此对象也必须声明为静态的)
private static final Hungry HUNGRY = new Hungry();
//提供公共的静态的方法,返回类的对象
public static Hungry getInstance() {
return HUNGRY;
}
}
懒汉式
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
//懒汉式单例
//道高一尺,魔高一丈,还是没能解决反射造成的安全问题,想解决得看枚举
public class LazyMan {
//这个的目的是解决俩次都是调用反射创建对象不安全的问题
private static boolean delTwoFanShe = false;
private LazyMan(){
// System.out.println(Thread.currentThread().getName()+"ok");
synchronized (LazyMan.class) {
if(delTwoFanShe == false) {
delTwoFanShe = true;
} else {
throw new RuntimeException("不要试图使用反射破坏异常");
}
// if(lazyMan!=null) {
// //此方式是解决创建实例时一个用的getInstance(),另一个用的反射得到的,但是解决不了俩次都是通过反射获得的情况
// throw new RuntimeException("不要试图使用反射破坏异常");
// }
}
}
private volatile static LazyMan lazyMan = null;
//双重检测锁模式的懒汉式模式,简称DCL懒汉式
public static LazyMan getInstance() {
//上锁
if(lazyMan==null) {
synchronized (LazyMan.class) {
if(lazyMan==null) {
lazyMan = new LazyMan();//不是一个原子性操作
/**
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
* 假如不是按照123步骤执行的话,就是发生了指令重排,那么lazyMan就没有完成初始化操作
*/
}
}
}
return lazyMan; //如果不是按顺序执行123操作的话,此时lazyMan还没有完成构造,所以必须加上volatile来避免这种问题的发生
}
//我们写main函数来破坏,不断增强懒汉式的安全性
public static void main(String[] args) throws Exception {
// for(int i=0;i<10;i++) {
// new Thread(()->{
// LazyMan.getInstance();
// }).start();
// }
// LazyMan instance = LazyMan.getInstance(); //这是一般的获取方式
//我们得到自己设置的隐藏值,进行破坏
Field delTwoFanShe = LazyMan.class.getDeclaredField("delTwoFanShe");
delTwoFanShe.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan lazyMan = declaredConstructor.newInstance();//通过反射得到实例对象
//我们修改第一次的实例,来将值变成false,进行破坏
delTwoFanShe.set(lazyMan,false);
LazyMan lazyMan1 = declaredConstructor.newInstance();//俩次实例对象都由反射来实现,造成破坏
System.out.println(lazyMan);
System.out.println(lazyMan1);
}
}
静态内部类实现
//静态内部类实现
public class Holder {
private Holder() {
}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}