• 设计模式之单例设计模式


    一、何为单例设计模式

      单例模式,顾名思义就是单个例,程序中某个类只有一个实例存在。通常实在需要共享某个资源避免资源损耗的情况下使用到的。

    二、单例设计模式的代码实现

      一说到单例模式的概念,我们首先会想到下面的这种的写法

    public class SingleInstance {
        
        private static SingleInstance singleInstance;
        
        private SingleInstance(){
        }
        
        /**
         * 单例模式
         * @return
         */
        public static SingleInstance getSingleInstance(){
            if(singleInstance == null){
                singleInstance = new SingleInstance();
            }
            
            return singleInstance;
        }
        
    }

       把构造器设置为private方法,只有在类内部的方法中才能调用,外部无法进行调用创建实例。

      的确这种写法是最简单的写法,但是如果是在多线程的环境下会出现什么样的情况呢,假设有两个线程同时进入这个获取实例方法运行到 singleInstance == null的时候都会判断这个条件为真,这时候两个线程都会去创建对象实例,就会导致创建多个实例对象。面对这种情况我们首先想到的是将方法设置为同步方法便可以防止多个线程同时创建多个对象实例的情况。

      同步方法单例模式:

    public class SingleInstance {
        
        private static SingleInstance singleInstance;
        
        private SingleInstance(){    
        }    
        
        /** 
         *  单例模式 
         *  @return 
         */
        public synchronized static SingleInstance getSingleInstance() {
            if (singleInstance == null) {
                singleInstance = new SingleInstance();
            }
            return singleInstance;
        }
    
    }

      是的,这种方法已经能解决多个线程下创建多个对象实例的问题,在并发不大的的情况下这种写法是已经够用的,那让我们想想在并发量大的程序中,这样的程序会出现什么问题呢?假设有多个线程都需要获取这个对象实例,因为这个方法是同步的,所以多个线程就会排队进行执行,这样子就会造成线程方法执行的阻塞。这种情况可以通过同步块来解决。

      同步方法块的单例模式写法(懒汉式):

    public class SingleInstance {
        
        private static SingleInstance singleInstance;
        
        private SingleInstance(){
        }
        
        /**
         * 单例模式
         * @return
         */
        public synchronized SingleInstance getSingleInstance(){
            if(singleInstance == null){
                singleInstance = new SingleInstance();
            }
            
            return singleInstance;
        }
        
    } 

      这种单例模式的写法就是现在最通用的写法,在刚开始初始化时如果多个线程进入到方法需要创建对象,运行到synchronized (SingleInstance.class) 时就会进入排队同步执行,当第一个线程运行到if(singleInstance == null)这句时,判断为真就会执行创建代码,创建实例对象。之后排队的线程运行if(singleInstance == null)都是假的,因此就再不会创建对象。而之后的其他线程进入到方法时,在同步方法块外层的if(singleInstance == null)判断中就已经为假,因此便不会进入到同步方法块中创建对象,会直接返回对象,而不用进行排队,线程便不会进入到阻塞中。

      当然我们还可以采用静态变量初始化的方法来实现单例模式。

      静态的单例模式(饿汉式) 

    public class SingleInstance {
        
        private volatile static SingleInstance staticSingle = new SingleInstance();
    
        private SingleInstance(){
        }
        
        public static SingleInstance getStaticSingle(){ 
            
            return staticSingle; 
        }
        
    }
      volatile关键字能够确保当staticSingle变量对应的对象被创建时多个线程能够及时地感知到。

      采用这种方法,很简单,但是这种情况下程序启动初始化便要去创建对象,如果要创建的对象耗费内存很大,就会导致程序启动时变得很慢,而且程序一启动就会使内存处于使用较高的状态。

      单例设计模式是我们在程序中常见的一种设计模式,通过最简单的写法再到完美的单例模式的写法,可以看出一个简单的单例模式中也是蕴含许多原理在里面。

      

  • 相关阅读:
    Mysql存储引擎
    数据库事务的四大特性以及事务的隔离级别
    万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题
    万万没想到,JVM内存区域的面试题也可以问的这么难?
    SQL Server读取及导入Excel数据
    SQL Server加密与解密
    线程之间如何通信
    mybatis 批量更新 批量添加
    vue echarts 从后台获取数据形成饼图,柱状图,折线图
    vue 视频播放
  • 原文地址:https://www.cnblogs.com/huangweikun/p/6597209.html
Copyright © 2020-2023  润新知