单例模式

饿汉式 可能会浪费空间

//饿汉式单例模式
public class Hungry {

    //可能会浪费空间
    private byte[] data1=new byte[1024];
    private byte[] data2=new byte[1024];
    private byte[] data3=new byte[1024];
    private byte[] data4=new byte[1024];

    public Hungry(){

    }

    private final static Hungry HUNGRY=new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }
}

DCL懒汉式 用的时候再加载

单线程

多线程 加锁两次检测 DCL懒汉式 new LazyMan()不是原子性操作 三步操作 指令重排 ==>加volatile关键字
ifif synchronized

//懒汉式单例模式
public class Lazy {

    private static boolean key=false;  //加密关键字

    private Lazy(){
        synchronized (Lazy.class){
            if(key==false)
            {
                key=true;
            }else
            {
                throw new RuntimeException("不要使用反射破坏异常");
            }
        }
    }
    private static volatile Lazy LAZY;

    public static Lazy getInstance(){
        //加锁 双重检测模式的 懒汉式单例 DCL懒汉式  原子性操作
        if(LAZY==null)
        {
            synchronized (Lazy.class){
                if(LAZY==null){
                    LAZY=new Lazy();  //不是原子性操作
                    /*
                    * 1. 分配内存空间
                    * 2. 执行构造方法初始化对象
                    * 3. 把这个对象指向这个空间
                    *
                    * 正确:123
                    * 错误:132 如果另一条线程B,在第三步时判断为非空 此时没有完成构建  空间中是虚无的 +volatile
                    * */
                }
            }
        }
        return LAZY;
    }
   /* //单线程下可以使用,但是多线程下不行
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                Lazy.getInstance();
            }).start();
        }
    }*/

    //反射可以破坏这种单例==>解决
    /*
    * */
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Lazy instance = Lazy.getInstance();
        //Lazy instance2 = Lazy.getInstance();
        Constructor<Lazy> declaredConstructors = Lazy.class.getDeclaredConstructor();

        //破坏加密关键字
        Field key = Lazy.class.getDeclaredField("key");
        key.setAccessible(true);
        key.set(instance,false);

        declaredConstructors.setAccessible(true); //无视私有构造器
        //Lazy instance = declaredConstructors.newInstance();
        Lazy instance2 = declaredConstructors.newInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
/*
并发情况下出现问题
Thread-1 ok
Thread-5 ok
Thread-4 ok
Thread-3 ok
Thread-0 ok
Thread-2 ok*/

静态内部类

//静态内部类  不安全
public class Holder {
    public Holder() {
    }

    public static Holder getInstance(){
        return InnerClass.HOLDER;
    }
    public static class InnerClass{
        private static final Holder HOLDER=new Holder();
    }
}

枚举类

//enum 枚举 本身也是一个class 只不过继承了枚举的类
public enum EnumSingle {
    INSTANCE;
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}
class test{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingle instance = EnumSingle.INSTANCE;
       // EnumSingle instance2 = EnumSingle.INSTANCE;
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();

        System.out.println(instance);
        System.out.println(instance2);
    }
}

/*
 通过jad.exe反编译发现没有无参的构造方法,只有有参构造方法

    Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
        at com.ji.demo03.test.main(EnumSingle.java:19)
*/

posted @ 2022-01-18 23:08  一刹流云散  阅读(25)  评论(0编辑  收藏  举报