zoukankan      html  css  js  c++  java
  • 单例模式-Singleton

    1、饿汉式:

    /**
     * 单例:饿汉式
     * 缺点:可能会浪费空间
     */
    public class Singleton_Hurry {
        private static final Singleton_Hurry HURRY = new Singleton_Hurry();
    
        //构造器私有化
        private Singleton_Hurry() {
            System.out.println("成功创建对象!"+System.currentTimeMillis());
        }
    
        /**
         * 提供公有方法来获取实例
         * @return
         */
        public static Singleton_Hurry getInstance() {
            return HURRY;
        }
    
        public static void main(String[] args) {
            Singleton_Hurry h1 = Singleton_Hurry.getInstance();
            Singleton_Hurry h2 = Singleton_Hurry.getInstance();
            System.out.println(h1.hashCode()); //1265094477
            System.out.println(h2.hashCode()); //1265094477
        }
    }
    

    image


    2、懒汉式:

    /**
     * 单例:懒汉
     * 这种写法在单线程上是可以,但在多线程下会出现并发问题
     */
    public class Singleton_Lazy {
        //构造器私有化
        private Singleton_Lazy() {
            System.out.println(Thread.currentThread().getName()+"ok!");
        }
    
        private static Singleton_Lazy LAZY;
    
        public static Singleton_Lazy getInstance() {
            if (LAZY == null) {
                LAZY = new Singleton_Lazy();
            }
            return LAZY;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    Singleton_Lazy.getInstance();
                }).start();
            }
        }
    }
    
    

    image


    支持多线程的懒汉式:

    /**
     * 单例:懒汉
     * 支持多线程(双重检测锁)
     * 问题:不加 volatile会造成指令成排(可能创建不了实例)
     */
    public class Singleton_Lazy {
        // 构造器私有化
        private Singleton_Lazy() {
            System.out.println(Thread.currentThread().getName() + "ok!");
        }
    
        // 避免指令重排
        private volatile static Singleton_Lazy lazy;
    
        public static Singleton_Lazy getInstance() {
            // 双重检测锁模式的单例 (DCL)
            if (lazy == null) {
                synchronized (Singleton_Lazy.class) {
                    if (lazy == null) {
                        lazy = new Singleton_Lazy();//它不是原子性操作
                        //1.分配内存空间 2.执行构造方法,初始化对象 3.把这个对象指向这个空间
                    }
                }
            }
            return lazy;
        }
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    Singleton_Lazy.getInstance();
                }).start();
            }
        }
    }
    

    image


    3、静态内部类

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

    前三种单例会被反射破解:

    public class Singleton_Lazy {
        // 构造器私有化
        private Singleton_Lazy() {
            System.out.println(Thread.currentThread().getName() + "ok!");
        }
    
        // 避免指令重排
        private volatile static Singleton_Lazy lazy;
    
        public static Singleton_Lazy getInstance() {
            // 双重检测锁模式的单例 (DCL)
            if (lazy == null) {
                synchronized (Singleton_Lazy.class) {
                    if (lazy == null) {
                        lazy = new Singleton_Lazy();//它不是原子性操作
                        //1.分配内存空间 2.执行构造方法,初始化对象 3.把这个对象指向这个空间
                    }
                }
            }
            return lazy;
        }
    
        public static void main(String[] args) throws Exception {
            Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
            System.out.println(lazy1.hashCode());
    
            // 使用反射来破坏单例
            Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
            constructor.setAccessible(true);//可以访问私有的构造器
            Singleton_Lazy lazy2 = constructor.newInstance();
            System.out.println(lazy2.hashCode());
        }
    }
    

    image

    解决单例被破解:

    /**
    * 三重检测锁
    */
    public class Singleton_Lazy {
        // 构造器私有化
        private Singleton_Lazy(){
            synchronized (Singleton_Lazy.class) {
                if (lazy != null) {
                   throw new RuntimeException("不要试图使用反射破坏异常!");
                }
            }
        }
    
        // 避免指令重排
        private volatile static Singleton_Lazy lazy;
    
        public static Singleton_Lazy getInstance() {
            // 双重检测锁模式的单例 (DCL)
            if (lazy == null) {
                synchronized (Singleton_Lazy.class) {
                    if (lazy == null) {
                        lazy = new Singleton_Lazy();//它不是原子性操作
                        //1.分配内存空间 2.执行构造方法,初始化对象 3.把这个对象指向这个空间
                    }
                }
            }
            return lazy;
        }
    
        public static void main(String[] args) throws Exception {
            Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
            System.out.println(lazy1.hashCode());
    
            // 使用反射来破坏单例
            Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
            constructor.setAccessible(true);//可以访问私有的构造器
            Singleton_Lazy lazy2 = constructor.newInstance();
            System.out.println(lazy2.hashCode());
        }
    }
    
    

    image

    此时创建对象也不是单例:

    public class Singleton_Lazy {
        // 构造器私有化
        private Singleton_Lazy(){
            synchronized (Singleton_Lazy.class) {
                if (lazy != null) {
                    throw new RuntimeException("不要试图使用反射破坏异常!");
                }
            }
        }
    
        // 避免指令重排
        private volatile static Singleton_Lazy lazy;
    
        public static Singleton_Lazy getInstance() {
            // 双重检测锁模式的单例 (DCL)
            if (lazy == null) {
                synchronized (Singleton_Lazy.class) {
                    if (lazy == null) {
                        lazy = new Singleton_Lazy();//它不是原子性操作
                        //1.分配内存空间 2.执行构造方法,初始化对象 3.把这个对象指向这个空间
                    }
                }
            }
            return lazy;
        }
    
        public static void main(String[] args) throws Exception {
           // Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
           // System.out.println(lazy1.hashCode());
    
            // 使用反射来破坏单例
            Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
            constructor.setAccessible(true);//可以访问私有的构造器
            Singleton_Lazy lazy2 = constructor.newInstance();
            System.out.println(lazy2.hashCode());
            Singleton_Lazy lazy3 = constructor.newInstance();
            System.out.println(lazy3.hashCode());   
        }
    }
    
    

    image

    解决方法:

    
    public class Singleton_Lazy {
        //红绿灯
        private static boolean baidou = false;
    
        // 构造器私有化
        private Singleton_Lazy() {
            synchronized (Singleton_Lazy.class) {
                if (baidou == false) {
                    baidou = true;
                } else {
                    throw new RuntimeException("不要试图使用反射破坏异常!");
                }
            }
        }
    
        // 避免指令重排
        private volatile static Singleton_Lazy lazy;
    
        public static Singleton_Lazy getInstance() {
            // 双重检测锁模式的单例 (DCL)
            if (lazy == null) {
                synchronized (Singleton_Lazy.class) {
                    if (lazy == null) {
                        lazy = new Singleton_Lazy();//它不是原子性操作
                        //1.分配内存空间 2.执行构造方法,初始化对象 3.把这个对象指向这个空间
                    }
                }
            }
            return lazy;
        }
    
        public static void main(String[] args) throws Exception {
            Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
            System.out.println(lazy1.hashCode());
    
            // 使用反射来破坏单例
            /*Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
            constructor.setAccessible(true);//可以访问私有的构造器
            Singleton_Lazy lazy2 = constructor.newInstance();
            System.out.println(lazy2.hashCode());*/
    
            Singleton_Lazy lazy3 = Singleton_Lazy.getInstance();
            System.out.println(lazy3.hashCode());
        }
    }
    

    image
    但还是能被反射破解

  • 相关阅读:
    Ubuntu 12.04 git server
    Moonlight不再继续?!
    Orchard 视频资料
    一恍惚八月最后一天了
    Box2D lua binding and Usage
    50岁还在编程,也可以是一种成功
    DAC 4.2 发布
    再次祝贺OpenStack私有云搭建成功
    vue项目快速搭建
    pdf.js使用详解
  • 原文地址:https://www.cnblogs.com/m987/p/15405661.html
Copyright © 2011-2022 走看看