• 3.设计模式单例模式(创建型) Java


    资料:https://gitee.com/chuanqi1995/java

    什么是单例模式?

    保证整个程序中只有一个类的实例叫做单例模式

    饿汉式

    饿汉式

    package hungry;
    
    /**
     * 饿汉式
     * 优点:效率高,线程安全
     * 缺点:有可能浪费空间
     */
    public class HungrySingleton {
        private static HungrySingleton hungrySingleton = new HungrySingleton();
    
        private HungrySingleton() {
        }
    
        public static HungrySingleton get(){
            return hungrySingleton;
        }
    }
    

    饿汉式 - 静态代码块

    package hungry;
    
    public class HungryStaticSingleton {
        private static HungryStaticSingleton hungryStaticSingleton;
        private HungryStaticSingleton() {
        }
        static {
            hungryStaticSingleton = new HungryStaticSingleton();
        }
        public static HungryStaticSingleton get(){
            return hungryStaticSingleton;
        }
    }
    

    懒汉式

    懒汉式

    package lazy;
    
    /**
     * 懒汉式
     * 优点:节省空间,线程安全
     * 缺点:效率太慢
     */
    public class LazySingleton {
        private static LazySingleton lazySingleton = null;
        private LazySingleton() {
        }
        public synchronized static LazySingleton get(){
            if(null == lazySingleton){
                return new LazySingleton();
            }
            return lazySingleton;
        }
    }
    

    懒汉式 - 双重检查锁

    package lazy;
    
    /**
     * 懒汉式 - 双重检查锁
     * 优点:线程安全,节省空间
     * 缺点:代码可读性差
     */
    public class LazyDoubleCheckSingleton {
        private static volatile LazyDoubleCheckSingleton lazySingleton = null;
        private LazyDoubleCheckSingleton() {
        }
        public static LazyDoubleCheckSingleton get(){
            // 校验是否加锁
            if(null == lazySingleton){
                synchronized (LazyDoubleCheckSingleton.class){
                    // 校验是否可以实例化
                    if(null == lazySingleton){
                        lazySingleton = new LazyDoubleCheckSingleton();
                        // 有指令重排序问题
                        // lazySingleton = new LazyDoubleCheckSingleton(); 这行代码 在JVM底层有三个操作
                        // 1、开辟空间
                        // 2、对象实例化new
                        // 3、指针指向
                    }
                }
            }
            return lazySingleton;
        }
    }
    

    懒汉式 - 内部类

    package lazy;
    
    /**
     * 懒汉式 - 内部类
     * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
     * 缺点:可读性又变差了
     */
    public class LazyStaticInnerClassSingleton {
    
        private LazyStaticInnerClassSingleton(){
            if(LazyHolder.instance != null){
                throw new RuntimeException("非法访问");
            }
        }
        public static LazyStaticInnerClassSingleton get(){
            return LazyHolder.instance;
        }
        private static class LazyHolder{
            private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
        }
    }
    

    注册式

    注册式 - 枚举

    package register;
    
    /**
     * 注册式 - 枚举类
     * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
     * 缺点:如果枚举类多的话,浪费内存
     */
    public enum EnumSingleton {
        INSTANCE;
        public static EnumSingleton get(){
            return INSTANCE;
        }
    }
    

    注册式 - 容器

    package register;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 注册式 - 容器类
     * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
     * 缺点:可以被反序列化破坏
     */
    public class ContainerSingleton {
        private ContainerSingleton(){
    
        }
        private static volatile Map<String, Object> ioc = new HashMap<>();
        public static Object get(String className) throws Exception {
            if(!ioc.containsKey(className)){
                synchronized (ContainerSingleton.class){
                    if(!ioc.containsKey(className)){
                        Object o = Class.forName(className).newInstance();
                        ioc.put(className, o);
                        return ioc.get(className);
                    }else{
                        return ioc.get(className);
                    }
                }
            }else {
                return ioc.get(className);
            }
        }
    
    
    }
    
    package register;
    
    import java.io.Serializable;
    
    public class User {
    }
    

    ThreadLocal式

    ThreadLocal式

    package threadlocal;
    
    public class ThreadLocalSingleton {
        private ThreadLocalSingleton(){
    
        }
        private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal<ThreadLocalSingleton>(){
            @Override
            protected ThreadLocalSingleton initialValue() {
                return new ThreadLocalSingleton();
            }
        };
        public static ThreadLocalSingleton get(){
            return threadLocal.get();
        }
    }
    

    问题

    反射

    被反射破坏

    package lazy;
    
    /**
     * 懒汉式 - 内部类
     * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
     * 缺点:可读性又变差了
     */
    public class LazyStaticInnerClassSingleton {
    
        private LazyStaticInnerClassSingleton(){
    
        }
        public static LazyStaticInnerClassSingleton get(){
            return LazyHolder.instance;
        }
        private static class LazyHolder{
            private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
        }
    }
    
    package lazy;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Constructor;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            LazyStaticInnerClassSingleton l = LazyStaticInnerClassSingleton.get();
            System.out.println(l);
    
            Class<LazyStaticInnerClassSingleton> clazz = LazyStaticInnerClassSingleton.class;
            Constructor<LazyStaticInnerClassSingleton> declaredConstructor = clazz.getDeclaredConstructor(null);
            declaredConstructor.setAccessible(true);
            LazyStaticInnerClassSingleton lazyStaticInnerClassSingleton = declaredConstructor.newInstance();
            System.out.println(lazyStaticInnerClassSingleton);
        }
    }
    

    防止被反射破坏

    package lazy;
    
    /**
     * 懒汉式 - 内部类
     * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
     * 缺点:可读性又变差了
     */
    public class LazyStaticInnerClassSingleton {
    
        private LazyStaticInnerClassSingleton(){
            if(LazyHolder.instance != null){
                throw new RuntimeException("非法访问");
            }
        }
        public static LazyStaticInnerClassSingleton get(){
            return LazyHolder.instance;
        }
        private static class LazyHolder{
            private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
        }
    }
    

    反序列化

    被反序列化破坏

    package register;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 注册式 - 容器类
     * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
     * 缺点:可以被反序列化破坏
     */
    public class ContainerSingleton {
        private ContainerSingleton(){
    
        }
        private static volatile Map<String, Object> ioc = new HashMap<>();
        public static Object get(String className) throws Exception {
            if(!ioc.containsKey(className)){
                synchronized (ContainerSingleton.class){
                    if(!ioc.containsKey(className)){
                        Object o = Class.forName(className).newInstance();
                        ioc.put(className, o);
                        return ioc.get(className);
                    }else{
                        return ioc.get(className);
                    }
                }
            }else {
                return ioc.get(className);
            }
        }
    
    
    }
    
    package register;
    
    import java.io.Serializable;
    
    public class User implements Serializable {
    
    }
    
    package register;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            User u1 = (User) ContainerSingleton.get("register.User");
    
            // 序列化 内存中的Java对象 -> 磁盘
            // 反序列化 磁盘 —> 内存中的Java对象
    
            // 序列化
            FileOutputStream fileOutputStream = new FileOutputStream("obj.user");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(u1);
            fileOutputStream.close();
            objectOutputStream.close();
    
            // 反序列化
            FileInputStream fileInputStream = new FileInputStream("obj.user");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            User u2 = (User) objectInputStream.readObject();
            fileInputStream.close();
            objectInputStream.close();
    
            System.out.println(u1);
            System.out.println(u2);
        }
    }
    

    防止被反序列化破坏

    package register;
    
    import java.io.Serializable;
    
    public class User implements Serializable {
        private Object readResolve() throws Exception {
            return ContainerSingleton.get("register.User");
        }
    }
    

    总结

    只有注册式 - 枚举不会被反射破坏和反序列化破坏,其余都会

  • 相关阅读:
    Java学习之路----计算圆形的面积和周长
    数据库系统的基本组成内容
    软件测试的含义以及测试的对象
    wg sync.WaitGroup执行顺序
    go channel
    字符串操作
    scanf
    py停止工作
    jira索引失败
    py kafka
  • 原文地址:https://www.cnblogs.com/chuanqi1995/p/16015312.html
Copyright © 2020-2023  润新知