单例模式:确保一个类在内存中最多只有一个实例,并提供一个全局访问点
一、单例模式必备条件:
1.构造器私有化,杜绝外界使用new创建对象
2.获取单例对象的静态方法,多个线程来访问也是返回一个实例
二、使用场景
有些对象只需要创建一个,线程池、缓存、硬件设备;比如对于多个程序使用同一个配置信息对象时,就需要确保该对象的唯一性。
如何保证唯一性:
1)不允许其他程序用new创建该对象
2)在该类中创建一个本类实例
3)对外提供一个方法让其他程序可以获取该类对象
步骤:
1)私有化该类的构造函数
2)通过new在本类中创建一个本类对象
3)定义一个共有的方法,将创建的对象返回
三、代码演示,及优化
package com.qa.danli; /** * 经典单例模式 * 存在的问题:如果多线程多个实例会造成冲突,结果的不一致性等问题(比如第一个调用还没实例化完后第二个开始调用) */ public class DanLiFactory { private static DanLiFactory uniqeInstance = null; //构造器私有化,杜绝了外界使用new创建对象 private DanLiFactory(){ } //获取单例对象的静态方法,多个线程来访问也是返回一个实例 public static DanLiFactory getInstance() { if(uniqeInstance == null) { uniqeInstance = new DanLiFactory(); } return uniqeInstance; } } //单例饿汉模式 ——》类一加载,对象就存在了 public class Single { private static Single single=new Single(); private Single(){} public static Single getInstance(){ return single; } } /** * 单例模式——》懒汉式——》延迟加载形式 *类加载进来没有对象,只有调用了getInstance方法时,才会创建对象 */ public class Single { private static Single single=null; public static Single getInstance() { if(single==null){ single=new Single(); } return single; } } package com.qa.danli; /** * 解决多线程多个实例造成的冲突,结果的不一致性添加Synchronized(同步锁) * 缺点:如果单例的类经常调用synchronized因为有同步锁所以特别耗资源 * 使用于对单例类使用次数比较少不是很频繁的 */ public class DanLiFactorySynchronized { private static DanLiFactorySynchronized uniqeInstance = null; //构造器私有化,杜绝了外界使用new创建对象 private DanLiFactorySynchronized(){ } public static synchronized DanLiFactorySynchronized getInstance() { if(uniqeInstance == null) { uniqeInstance = new DanLiFactorySynchronized(); } return uniqeInstance; } } package com.qa.danli; /** * 解决同步锁导致的资源消耗与多线程异常,使用“急切创建实例” * 缺点:可能在项目中没有调用到,开始就创建了浪费些内存资源 */ public class DanLiFactoryJiqie { private static DanLiFactoryJiqie uniqeInstance = new DanLiFactoryJiqie(); //构造器私有化,杜绝了外界使用new创建对象 private DanLiFactoryJiqie(){ } public static synchronized DanLiFactoryJiqie getInstance() { if(uniqeInstance == null) { uniqeInstance = new DanLiFactoryJiqie(); } return uniqeInstance; } } package com.qa.danli; /** * 多线程问题优化3——推荐 * 双重检查加锁法 */ public class DanLiFactorySCJCJS { //volatile给编译器用的,为了处理线程安全 private volatile static DanLiFactorySCJCJS uniqeInstance =null; //构造器私有化,杜绝了外界使用new创建对象 private DanLiFactorySCJCJS(){ } public static synchronized DanLiFactorySCJCJS getInstance() { if(uniqeInstance == null) { synchronized (DanLiFactorySCJCJS.class) { if(uniqeInstance==null){ uniqeInstance=new DanLiFactorySCJCJS(); } } } return uniqeInstance; } }
