• 单例模式


      我们在写程序的时候,大部分时候,会把类定义成为public类型的,那么任何类都可以随意的创建该类的对象。但是有时候,这种做法并没有任何意义,频繁的创建对象和回收对象造成内存损耗,所以就有了单例模式

      一个类只能创建一个对象,则这个类被成为单例类,这种模式被成为单例模式

      单例模式的原则是:

        1.把类的构造方法隐藏起来

        2.创建一个方法,这个方法可以创建一个(并且只有一个)自己的实例

        3.这个方法可以被外部使用

      单例模式分为:懒汉模式、饿汉模式和等级模式

      懒汉模式:

     
       /**
         * 懒汉模式,特征是待到使用时,才创建该类对象
         */

    public class Single {
    
        // 定义一个类变量,来存储该类对象
        private static Single single;
    
        // 隐藏构造器
        private Single() {
    
        }
    
        // 定义一个方法供外部调用,返回一个该类唯一的对象
        public static Single getSingle() {
            if (single == null) {
                single = new Single();
            }
            return single;
        }
    
        public static void main(String[] args) {
            Single s1 = Single.getSingle();
            Single s2 = Single.getSingle();
            if (s1 == s2) {
                System.out.println("Single类是单例模式");
            } else {
                System.out.println("Single类不是单例模式");
            }
        }
    }

      饿汉模式:

    
    
       /**
         * 饿汉模式 饿汉模式特征是在类加载时候已经创建好实例待调用,并且该实例不可变
         */

    public
    class Single { // 直接创建该类的实例,该实例不可变 private static final Single single = new Single(); // 隐藏构造函数 private Single() { } // 创建一个方法供外部调用,返回该类的实例 public static Single getSingle() { return single; } public static void main(String[] args) { Single s1 = Single.getSingle(); Single s2 = Single.getSingle(); if (s1 == s2) { System.out.println("Single类是单例模式"); } else { System.out.println("Single类不是单例模式"); } } }

      登记模式:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
         /**
         * 单例模式之登记模式,特征是事先维护一组map存放一个实例,当创建实例时,先查看map是否存在,如果存在,则直接返回,如果不存在,则先存入,再返回
         */
    public class Single {
        
        // 定义一个map,用来登记实例
        private static Map<String, Single> map = new HashMap<String, Single>();
        // 先在map中存放一个Single实例
        static {
            Single single = new Single();
            map.put(single.getClass().getName(), single);
        }
    
        // 隐藏构造器
        private Single() {
    
        }
    
        // 定义一个方法供外部调用,用来返回实例,需要传入一个参数作为map中的“键”
        public static Single getSingle(String key) {
            // 如果传入的参数为null,则讲类名称赋值给它
            if (key == null) {
                key = Single.class.getName();
            }
            // 根据传入的“键”判断是否存在“值”,如果不存在,则将该
            if (map.get(key) == null) {
                try {
                    map.put(key, (Single) Class.forName(key).newInstance());
                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return map.get(key);
        }
    
        public static void main(String[] args) {
            Single single1 = Single.getSingle(null);
            Single single2 = Single.getSingle(null);
            System.out.println(single1 == single2);
        }
    }        

    单例中的线程安全问题

             饿汉式这种一开始就创建实例的方式,线程是安全的,懒汉式则不同,看代码

    public class Single {
    
        // 定义一个类变量,来存储该类对象
        private static Single single;
    
        // 隐藏构造器
        private Single() {
    
        }
    
        // 定义一个方法供外部调用,返回一个该类唯一的对象
        public static Single getSingle() {
            if (single == null) {  //当线程执行到这里挂起时,别的线程获取执行权限执行到这里,还会继续给single创建实例,这样就造成了线程安全问题。
                single = new Single();
            }
            return single;
        }
    
        public static void main(String[] args) {
            Single s1 = Single.getSingle();
            Single s2 = Single.getSingle();
            if (s1 == s2) {
                System.out.println("Single类是单例模式");
            } else {
                System.out.println("Single类不是单例模式");
            }
        }
    }

      为了避免懒汉式的线程安全问题,我们需要给他加上代码同步

    public class ThreadForSingle {
        public static void main(String[] args) {
    
        }
    }
    
    class Single {
    
        private Single() {
        }
    
        private static Single single = null;
    
        public static Single getSingle() {
    
            synchronized (Single.class) {
                if (single == null) {
                    single = new Single();
                }
            }
            return single;
        }
    }

      当线程进来判断出single为null时,遇到问题挂起,其余的线程则无法进来,这样就保证了线程的安全

      

  • 相关阅读:
    RESTful API 设计指南
    理解RESTful架构
    django-mysqlclient_1193错误
    获取当前脚本所在的目录和路径
    20191007
    20191005
    20191001
    20190927
    20190922
    莫比乌斯反演证明
  • 原文地址:https://www.cnblogs.com/xs104/p/4464320.html
Copyright © 2020-2023  润新知