单例模式-创建型

单例分为懒汉式和饿汉式

简单代码块

懒汉式

个人解释懒加载生成对象,即用到的时候才去实例化
单线程

public class Lazy {
    private static Lazy l;

    private Lazy() {

    }

    public static Lazy getH(){
        if(l==null){
            l=new Lazy();
        }
        return l;
    }
}
//懒汉式 双检锁 多线程
public class SingleTest {
    private static boolean key = false;
    
    //volatile指令实现有序性,防止指令重排序,否则在双检锁中获取到null
    //eg:第一个线程进入singleTest=new SingleTest(); 但是顺序是先引用赋值未初始化
    //第二个线程进入发现第一个判断singleTest!=null 返回未初始化的singleTest
    private static volatile SingleTest singleTest;

    private SingleTest(){
        synchronized (SingleTest.class){
            if (key==false){
                key=true;
            }
            else{
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
        System.out.println(Thread.currentThread().getName()+" ok");
    }
    public static SingleTest instance(){
        if(singleTest==null){
            synchronized (SingleTest.class){
                if(singleTest==null){
                    singleTest=new SingleTest();
                }
            }
        }
        return singleTest;
    }

    public static void main(String[] args) {
        try {
            //Java中有反射
//        LazyMan instance = LazyMan.getInstance();
            Field key = SingleTest.class.getDeclaredField("key");
            key.setAccessible(true);
            Constructor<SingleTest> declaredConstructor = 		SingleTest.class.getDeclaredConstructor(null);
            declaredConstructor.setAccessible(true); //无视了私有的构造器
            SingleTest instance1 = SingleTest.instance();
            key.set(instance1,false);
            SingleTest lazyMan1 = declaredConstructor.newInstance();


            SingleTest instance = declaredConstructor.newInstance();

            System.out.println(instance);
            System.out.println(lazyMan1);
            System.out.println(instance == lazyMan1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

饿汉式

普通饿汉式

public class Hungry {
    private static final Hungry h=new Hungry();

    private Hungry() {
        
    }
  
    public static Hungry getH(){
        return h;
    }
}

静态内部类 天生线程安全

注意使用ObejectOutputStream oos序列化前后导致对象不是同一地址,可以重写readResolve()方法解决

//静态内部类
public class SingleStatic {

    private static class Inner{
        private static final SingleStatic singleStatic=new SingleStatic();
    }
    private SingleStatic(){

    }
    public static SingleStatic instance(){
        return Inner.singleStatic;
    }
}

Enum枚举类型 天生线程安全 序列化也能包装同一对象

public enum  EnumSingleTest {
    INSTANCE;
    int a;
    public EnumSingleTest instance() {
        return INSTANCE;
    }

    public static void main(String[] args) {
        try {

            Constructor<EnumSingleTest> declaredConstructor = EnumSingleTest.class.getDeclaredConstructor(String.class,int.class);
            declaredConstructor.setAccessible(true);
            EnumSingleTest enumSingleTest = declaredConstructor.newInstance();
            System.out.println(enumSingleTest);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
posted @ 2021-07-30 16:44  8023渡劫  阅读(44)  评论(0)    收藏  举报