每天一模式——单例模式

一、单例模式是为了控制类只有一个实例对象,通常在以下两种情况需要考虑使用单例模式:

1、业务逻辑的需求

2、性能的考虑

二、单例模式的机构图:


三、单例模式的几种实现形式:

1、形式一

public class Singleton2 {
	private static Singleton2 instance;
	private Singleton2() {
	}
	
	public  static Singleton2 getInstance(){
		if(instance==null){
			instance = new Singleton2();
		}
		return instance;
	}
}
2、形式二

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

}
注意:对于第一种形式来说,其最大的问题是不适合于多线程模式。

3、形式三——改进形式一,使其在多线程模式下能正常运行:

public class Singleton2 {
	private static Singleton2 instance;
	private Singleton2() {
	}
	
	public synchronized  static Singleton2 getInstance(){
		if(instance==null){
			instance = new Singleton2();
		}
		return instance;
	}
}
加上关键字synchronized后,确实能保证线程的安全,但是存在的问题是,验证影响效率,因为同步整个方法,会使得所有的线程需要顺序执行,不能并发执行。

4、形式四——修正形式三,提高效率:

public class Singleton2 {
	private volatile static Singleton2 instance;
	private Singleton2() {
	}
	
	public  static Singleton2 getInstance(){
		if(instance==null){
			synchronized(Singleton2.class){
				if(instance==null){
					instance = new Singleton2();
				}
			}
			
		}
		return instance;
	}
}
这段代码的核心是:双重检查并加锁。双重检查的作用在于不需要同步整个方法,可以并发执行程序,并且在加锁的情况下可以保证线程的安全。这个地方还需要注意的关键字是volatile,但是该关键字仅仅能保证读取的是最新指值,而无法保证原子性操作,更不能保证同步。因为在JVM中每个线程有自己的内存空间,正常情况下,该内存区间会保存堆中变量的一个副本,然后完成操作后写回堆中,使用volatile关键能保证不使用线程的缓存,而直接读取堆中的值。从而保证每次读取的值是最新的值,但是有可能同时两个线程读取了该变量,然后再依次修改该变量。



猜你喜欢

转载自blog.csdn.net/lxpblsc/article/details/11488801