简介

单例模式 有饿汉式 & 懒汉式 等等.

参考链接

https://www.bilibili.com/video/BV1K54y197iS

饿汉式

简单来说, 一上来就把所有的资源进行了申请, 优点, 简单. 缺点, 如果资源比较大, 容易浪费资源.

懒汉式

需要的时候, 才会去申请资源.

code

饿汉式, 非线程安全

public class Hungry {
    private Hungry(){}

    private final static Hungry HUNGRY = new Hungry();

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

懒汉式, 非线程安全

public class LazyMan {
    private LazyMan(){}

    private static LazyMan lazyMan;

    private static LazyMan  getInstance() {
        if(lazyMan == null){
            lazyMan = new LazyMan(); // 需要的时候才会去申请资源.
        }
        return lazyMan;
    }
}

静态内部类实现的单例模式 非线程安全

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

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

懒汉式, 线程安全

package single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * Created by lee on 2021/5/30.
 */
public class LazyManThread {
    private static boolean qingjiang = false;

    private LazyManThread(){
        synchronized (LazyManThread.class){
            if(qingjiang == false){ // 防止反射造成的单例失效.
                qingjiang = true;
            }else{
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
            if(lazyMan != null){ // 防止反射造成的单例失效.
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
        System.out.println(Thread.currentThread().getName() + "OK");
    }

    private static LazyManThread lazyMan;

    private static LazyManThread  getInstance() {
        // DCL 懒汉式  双重检测锁
        if(lazyMan == null) {
            synchronized (LazyManThread.class){ // 加锁
                if(lazyMan == null){
                    lazyMan = new LazyManThread();
                    /*
                    * 1. 分配内存空间
                    * 2. 执行构造方法, 初始化对象
                    * 3. 把这个对象指向这个空间
                    * 123 132 由于这个顺序不一定, 也肯造成线程不安全. 使用双重锁来避免这个问题.
                    * */
                }
            }
        }
        if(lazyMan == null){
            lazyMan = new LazyManThread();
        }
        return lazyMan;
    }

//    public static void main(String[] args) {
//        for(int i=0; i<10; i++){
//            new Thread(()->{
//                LazyManThread.getInstance();
//            }).start();
//        }
//    }
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //LazyManThread instance = LazyManThread.getInstance();
        Field qingjiang = LazyManThread.class.getDeclaredField("qingjiang");
        qingjiang.setAccessible(true);

        Constructor<LazyManThread> declaredConstructor = LazyManThread.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyManThread instance2 = declaredConstructor.newInstance();
        qingjiang.set(instance2, false);
        LazyManThread instance3 = declaredConstructor.newInstance();
        //System.out.println(instance);
        System.out.println(instance2);
        System.out.println(instance3);

    }
}

TIPS

对于使用enum的对象来说, 可以一定程度上保证进行单例模式

package single;



/**
 * Created by lee on 2021/5/30.
 */
// enum使用
public enum EnumSingle {
    INSTANCE;
    public EnumSingle getInstance() {
        return INSTANCE;
    }

}
class Test{
    public static void main(String[] args) {
        EnumSingle instance1 = EnumSingle.INSTANCE;
        EnumSingle instance2 = EnumSingle.INSTANCE;

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

IDEA自带了一套反编译的功能, 但是不是特别好, 可以使用java 自带的反编译系统.

javap -p XXX.class

也不一定成功, 可以使用 jad 来进行反编译. 要下一个新代码, 比较繁琐, 暂时不测试了.

posted on 2021-05-30 19:12  HDU李少帅  阅读(47)  评论(0编辑  收藏  举报