单例模式

单例模式,顾名思义,就是整个程序中只有一个实例对象,确保某个类中只有一个实例,而且自行实例化并为整个系统提供这个实例。
那什么时候能用到单例模式呢?对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。
单例模式的特点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
单例模式有多种写法,各有优劣。
饿汉式写法

public class Singleton {
	
    private static final Singleton singleton = new Singleton();
    
    //限制产生多个对象
    private Singleton(){ }
    
    public static Singleton getSingleton() {
    	return singleton;
    }
}

类在加载时会实例化对象,而且这个类在整个生命周期中只会加载一次,保证了单例。同时也没有线程同步的问题。但由于在类加载时就完成实例化,如果全程没有用到这个实例,会造成资源浪费。
懒汉式写法

public class Singleton {

	private static Singleton singleton;
	
	private Singleton(){}
	
	public static Singleton getSingleton(){
	    // 被动创建,在真正需要使用时才去创建
	    if (singleton == null) {
	        singleton = new Singleton();
	    }
	    return singleton;
	}
}

可以看出,单例被延迟加载,虽然避免了资源浪费,但造成了更大的问题。线程不安全,若有多个线程同时进入了if (singleton == null)时,这个单例就不是单例了。
为了线程安全,我们通过双重锁实现单例模式:

public class Singleton {

	private static volatile Singleton singleton;
	
	private Singleton(){}
	
	public static Singleton getSingleton(){
	    //第一次校验singleton是否为空
	    if (singleton == null) {
	        synchronized (Singleton.class) {
	        	//第二次校验singleton是否为空
				if(singleton == null)
					singleton = new Singleton();
			}
	    }
	    return singleton;
	}
}

双重锁模式,第一次防止出现多个实例,第二次防止多线程问题。但在创建对象时可能有重排序问题(singleton = new Singleton();),所以加上volatile关键字来禁用重排序,解决该问题,不但线程安全,而且提高了程序性能。
静态内部类式写法

public class Singleton {

	//静态内部类初始化对象
	private static class Inner{
		private static final Singleton SINGLETON = new Singleton();
	}
	
	private Singleton() { }
	
	public static Singleton getSingleton() {
		return Inner.SINGLETON;
	}
}

这种写法当有外部方法第一次调用getSingleton方法时,静态内部类才会初始化对象,避免浪费资源,利用classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,而且内部类是私有的,除了getSingleton()外无法访问,保证了对象的唯一性。
总结一下:
单例模式优点:

  1. 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
  2. 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决(在JavaEE中采用单例模式时需要注意JVM垃圾回收机制)。
  3. 单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
  4. 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

缺点:

  1. 单例模式没有接口,扩展困难,只能通过修改代码的方式来扩展。
  2. 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出。
  3. 如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值