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

    单例模式的概念及应用

    单例类需要满足以下几个点

    • 1.单例类只能有一个实例
    • 2.实例只能自己生成
    • 3.像其他所有对象提供这一实例

    单例模式的应用

    • 多线程情况下保证资源的一致性,例如多台打印机打印一个文件。

    单例模式的写法

    饿汉式

    线程安全

    public class EagerSingleton
    {
        private static EagerSingleton instance = new EagerSingleton();
        
        private EagerSingleton()
        {
            
        }
        
        public static EagerSingleton getInstance()
        {
            return instance;
        }
    }
    

    饿汉式就是在调用getInstance这个方法的时候实例直接被创建,并不进行判断实例是否为空。由于实例是被直接创建,所以并不可以延迟加载(Lazy Loading),容易产生垃圾对象。

    还有一个问题,饿汉式是如何保证线程安全的?

    假如线程1实例化一个EagerSingleton的同时线程2也在实例化,那么对象不就产生两个内存地址了嘛?事实上是java虚拟机帮我们解决了这个问题。

    JVM的解决办法

    当jvm遇到new这个关键字的时候,首先会检查符号引用是否已经存在常量池中,(这句话的意思就是新创建的对象是否已经存在),如果没有的话就开始为新建的对象分配内存。

    分配内存有两种方式:假如内存规整,就用第一种指针碰撞(Bump the Pointer),就是向空闲的内存区挪动一段位移。假如内存不规整,就采用空闲列表(Free List),从列表上选取一段足够大的内存。

    对象创建是很频繁的行为,如果线程1给A分配内存的时候,线程2也在给B分配内存,无论采取何种方式分配内存,都有可能将B的内存分配给A。

    解决问题的两种方案:一种是对分配动作同步处理,采用CAS配上失败重试的方式保证更新操作的原子性。另一种将先对线程分配空间,在他们自己的空间里进行操作,称之为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),分配空间用完时,才需要同步锁定。

    懒汉式

    顾名思义,是可以Lazy Loading的,但是线程不安全

    public class LazySingleton
    {
        private static volatile LazySingleton instance = null;
        
        private LazySingleton(){}
        public static LazySingleton getInstance()
        {
            if (instance == null)
                instance = new LazySingleton();
            return instance;
        }
    }
    

    双检索

    线程安全,Lazy Loading

    public class DoubleCheckLockSingleton
    {
        private static DoubleCheckLockSingleton instance = null;
        
        private DoubleCheckLockSingleton(){}
        
        public static DoubleCheckLockSingleton getInstance()
        {
            if (instance == null)
            {
                synchronized (DoubleCheckLockSingleton.class)
                {
                    if (instance == null)
                        instance  = new DoubleCheckLockSingleton();
                }
            }
            return instance;
        }
    }
    

    单例模式的应用之Mybatis

    Mybatis中事务是通过SqlSession来处理的,每次应用想要访问数据库,都需要通过SqlSessionFactory来创建SqlSesson。

    如果多次创建同一个数据库的SqlSessionFactory,就会打开更多数据库连接,数据库连接资源很快就会耗尽。

    所以一个数据库只对应一个SqlSessionFactory,那么肯定想到单例模式。

    public class SqlSessionFactoryUtil {
    	//SqlSessionFacory对象
    	private static SqlSessionFactory sqlSessionFactory;
    	//类线程锁
    	private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class;
    	//私有化构造参数
    	private SqlSessionFactoryUtil() {}
    	
    	public static SqlSessionFactory initSqlSessionFactory(){
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = null;
    		try {
    			inputStream = Resources.getResourceAsStream(resource);
    		} catch (IOException e) {
    			Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE,null,e);
    		}
    		synchronized (CLASS_LOCK) {
    			if (sqlSessionFactory == null) {
    				sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    			}
    		}
    		return sqlSessionFactory;
    	}
        /*
         * 打开SqlSession
         */
    	public static SqlSession openSqlSession(){
    		if (sqlSessionFactory == null) {
    			initSqlSessionFactory();
    		}
    		return sqlSessionFactory.openSession();
    	}
    }
    
  • 相关阅读:
    类的有参方法
    WPF 中的设备无关单位
    Skelta BPM.NET 2006 初探
    Reporting Services Handscript
    C语言I博客作业03
    C语言I博客作业02
    C++类的运算符重载和转换函数结合的问题
    C++ 函数返回类成员的问题
    kaggle 利用linear regression 进行房价预测
    android Could not open: c:\。。。。\.android/avd/XXXX.ini 问题和解决方法
  • 原文地址:https://www.cnblogs.com/bihanghang/p/9956862.html
Copyright © 2011-2022 走看看