zoukankan      html  css  js  c++  java
  • 设计模式之单例模式

    设计模式之单例模式

    1. 概念

    ​ 所谓单例模式,就是采取一定的方法使得系统中只存在某个类的一个实例,并且该类只提供一个获取对象实例的方法(静态方法);比如Hibernate的SessionFactory

    2.实现

    1.静态常量/静态代码块方法(饿汉式)

    类加载的时候就完成了实例化,不存在线程同步问题,但是如果至始至终这个对象都用不到,那就变成了内存的浪费,没有达到Lazy Loading的效果

    步骤:

    • 构造器私有化(外部无法通过new来创建对象)

    • 类的内部创建对象

    • 向外暴露一个公共的getInstance方法

      class Singleton{
      	//1.私有化构造器
          private Singleton(){}
          
          //2.类内部创建对象
          private final static Singleton instance = new Singleton();
          //或者将创建对象放在静态代码块中
          private static Singleton instance ;
          static{
              instance = new Singleton();
          }
          
          //3. 提供一个公共的方法获取对象
          public static Singleton getInstance(){
              return instance;
          }
          
          
      }
      

    2. 懒汉式(Lazy Loading的效果)

    1. 线程不安全

    class Singleton{
    	//1.私有化构造器
        private Singleton(){}
        //2.类内部定义对象
        private  static Singleton instance;   
        //3. 提供一个公共的方法获取对象
        public static Singleton getInstance(){
            if(instance == null){//需要时再创建,不会在类加载的时候创建
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    该方法只能在单线程下执行,多线程下有可能多个线程同时进入到 if 模块,以至于创建出多个实例,实际开发中不能使用这种方法

    2.线程安全,同步方法

    getInstance()方法中加上同步代码关键字synchronized来解决线程问题

        public static synchronized Singleton getInstance(){
            if(instance == null){//需要时再创建,不会在类加载的时候创建
                instance = new Singleton();
            }
            return instance;
        }
    

    效率过低,我们在创建对象实例的时候才需要同步,而这样的代码我们在之后的每次获取实例都会进行一次同步,方法进行同步的效率太低了

    3.双重检查

    volatile可以使共享变量一旦修改就刷新到内存里去,在getInstance方法中,通过synchronized同步来使得线程安全,当多个线程进入外层 if 时,会受到synchronized关键字作用,单个进入到内层 if 中,当instance被创建后,由于volatile的作用会立刻刷新到内存,等待的线程就会在内层 if 中判断false,即保证了单个实例创建,再后来的线程在外层 if 就false了,也解决了效率问题

    class Singleton{
    	//1.私有化构造器
        private Singleton(){}
        //2.类内部定义对象
        private  static volatile Singleton instance;  // volatile可以使共享变量一旦修改就刷新到内存里去
        //3. 提供一个公共的方法获取对象
        public static Singleton getInstance(){
            if(instance == null){//需要时再创建,不会在类加载的时候创建
                synchronized(Singleton.class){
                    if(instance==null){
               			 instance = new Singleton();                    
                    }
                }
            }
            return instance;
        }   
    }
    

    开发中可以使用

    4.静态内部类

    JVM在类加载的时候是线程安全的,并且类加载的时候,其静态内部类不会被加载,所以我们可以利用这一点来达到线程安全和Lazy Loading的效果

    class Singleton{
        //1.对象实例在内部类加载时被创建
        public static class SingletonInstance{
            private static final Singleton INSTANCE = new Singleton();
        }
        
    	//2.私有化构造器
        private Singleton(){} 
        //3. 提供一个公共的方法获取对象,调用该方法时,内部类第一次被加载,创建对象实例
        public static Singleton getInstance(){
            return SingletonInstance.INSTANCE;
        }   
    }
    

    开发中推荐使用

    5.枚举

    借助JDK1.5中添加的枚举来实现单例模式。不仅可以避免多线程同步问题,而且还能防止反序列化重新创建性的对象

    enum Singleton{
    	INSTANCE;
        public void play(){
            //code。。。
        }
    }
    
    //可以直接调用获取
    Singleton instance = Singleton.INSTANCE;
    //枚举中的方法也可以直接调用
    instance.play();
    

    开发中推荐使用

    3.应用场景

    • 需要经常创建、销毁的对象
    • 创建对象耗时过多或损耗资源过多的,但又经常用到的重量级对象
    • 工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等等)

    分析Runtime源码中使用的单例模式

  • 相关阅读:
    笔记-归并排序
    Repeated Substring Pattern
    Assign Cookies
    Number of Boomerangs
    Paint Fence
    Path Sum III
    Valid Word Square
    Sum of Two Integers
    Find All Numbers Disappeared in an Array
    First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/JIATCODE/p/13052496.html
Copyright © 2011-2022 走看看