学习笔记(11):第2章 架构师内功心法之设计模式 -单例模式详解(下)

立即学习:https://edu.csdn.net/course/play/28941/403598?utm_source=blogtoedu

利用内部类实现懒汉式单例模式

/**
 * ClassPath: LazyStaticInnerClassSingleton.class
 *            LazyStaticInnerClassSingleton$LazyHolder.class
 * 优点:写法优雅,利用了Java本身语法特点;性能高;避免了不必要的内存的浪费
 * 缺点:能够被反射机制破坏。
 * */
public class LazyStaticInnerClassSingleton {

    private LazyStaticInnerClassSingleton(){}

    public static LazyStaticInnerClassSingleton Instance(){
        return LazyHolder.INSTANCE;
    }

    private static class LazyHolder{

        private static final LazyStaticInnerClassSingleton  INSTANCE = new LazyStaticInnerClassSingleton();

    }
}

到此为止的单例模式都会被反射破坏。

import java.lang.reflect.Constructor;

/**
 * 反射都可以拿到类的构造方法即使他是私有方法
 * Declared 公开宣布的 公然的
 * Accessible 可进入的,可访问的*/
public class ReflectTest {

    public static void main(String[] args) {
        try {
            Class<?> clazz = LazyStaticInnerClassSingleton.class;
            Constructor c = clazz.getDeclaredConstructor(null);
            // 设置强制访问
            c.setAccessible(true);
            // 创建实例(破坏了单例模式)
            Object instance = c.newInstance();
            Object in = c.newInstance();
            System.out.println(instance);
            System.out.println(in);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}
/**
 * ClassPath: LazyStaticInnerClassSingleton.class
 *            LazyStaticInnerClassSingleton$LazyHolder.class
 * 优点:利用了Java本身语法特点;性能高;避免了不必要的内存的浪费; 不能够被反射机制破坏。
 * 缺点:写法不优雅,
 * */
public class LazyStaticInnerClassSingleton {

    private LazyStaticInnerClassSingleton(){
        if (LazyHolder.INSTANCE != null)
            throw new RuntimeException("不允许非法访问");
    }

    public static LazyStaticInnerClassSingleton Instance(){
        return LazyHolder.INSTANCE;
    }

    private static class LazyHolder{

        private static final LazyStaticInnerClassSingleton  INSTANCE = new LazyStaticInnerClassSingleton();

    }
}

注册式单例——将每一个实例都缓存到统一的容器中,使用唯一标识获取实例。

public enum  EnumSingleton {
     INSTANCE;

     private Object data;

    public void setData(Object data){
       this.data = data;
    }

    public Object getData(){
        return data;
    }

     public static EnumSingleton getInstance(){
         return INSTANCE;
     }
}
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 线程不安全
 * */
public class ContainerSingleton {

    private ContainerSingleton(){}

    private static Map<String, Object> ioc = new ConcurrentHashMap<>();

    public static Object getInstance(String className){

        Object instance = null;
        if (!ioc.containsKey(className)){
            try {
                instance = Class.forName(className).newInstance();
                ioc.put(className, instance);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //return ioc.get(className);
            return instance;
        }else {
            return ioc.get(className);
        }


    }

}

序列化:

把内存中对象的状态转化为字节码的形式;

把字节码通过IO输出流写到磁盘上;

内存对象状态就可以永久保存下来了;——持久化。

反序列化:

将持久化的字节码内容,通过IO输入流读到内存中来,转化成一个Java对象。

ThreadLocal单例——保证线程内部的全局唯一,且天生线程安全。

扫描二维码关注公众号,回复: 12428372 查看本文章
public class ThreadLocalSingleton {

    private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>(){
        @Override
        protected ThreadLocalSingleton initialValue() {
            return new ThreadLocalSingleton();
        }
    };

    private ThreadLocalSingleton(){}

    public static ThreadLocalSingleton getInstance(){
        return threadLocalInstance.get();
    }
}

单例模式的优点:

在内存中只有一个实例,减少了内存开销。

可以避免对资源的多重占用

设置全局访问点,严格控制访问

单例模式的缺点:

没有接口,扩展困难

如果要扩展单例对象,只有修改代码,没有其他途径。

总结:

1.私有化构造器

2.保证线程安全

3.延迟加载

4.防止序列化和反序列化破坏单例

5.防御反射攻击单例。

猜你喜欢

转载自blog.csdn.net/weixin_43222122/article/details/107586537