告别死记硬背懒汉式单例模式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Hanoch_wang/article/details/90645836

首先简单说一下单例模式,单例模式在使用时只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时、则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。好了定义方面就说到这吧,更详细的内容百度上有很多,大家可以找合适的,欢迎分享。

接着给出一段比较经典的代码:

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

是不是感觉比较简单,各大博客帖子这段代码出现的频率非常高,但是每当自己去重写的时候发现不是少加了static就是少加了一个判断。这种现象说明我们还没有真正理解懒汉模式的创建步骤,最近看到一段视频讲了这个,顿时茅塞顿开,写下来跟大家一起分享。

我将这段代码拆成一步一步的写:
           第一步:把构造方法私有化,使得其他类不能通过new实例化这个类的对象。

//第一步代码
public class SingleTon{
	
	private SingleTon() {}
	
}
 

第二步:但是外部是需要用到这个类的对象的,为了让外部获得此类的实例对象,我们可以对外提供一个获取对象的方法getInstance()。

//第二步代码
public class SingleTon{
	
	private SingleTon() {}
	
	public SingleTon getInstance() {
   
           return new SingleTon();
    
        }
}
 

第三步:增加对象是否已经被创建的判断,为了完成该步骤,创建一个全局变量instance

第四步:创建instance

//第三步、第四步代码
public class SingleTon{
	
	private SingleTon instance;
	
	private SingleTon() {}
	
	public SingleTon getInstance() {
		
          if(instance == null){
		     instance = new SingleTon();
	      }
	    
        return instance; 
    }

}
 

第五步:外部调用getInstance方法需要通过 对象.getInstance()方式调用,但是因为类的构造器被私有了,外部不能创建对象,所以在getInstance方法前面加上static.

第六步:由于变量instance需要被静态方法getInstance()调用,非静态变量不能被静态方法调用, 所以需要在instance前加上static,又因为instance对象是static的,所以必须用private修饰。因为如果用public修饰,外部就直接可以通过类名.instance访问。

//第五步、第六步代码
public class SingleTon {

	private static SingleTon instance; 
	
	private SingleTon() {
		
	}
	
	public static SingleTon getInstance() {
		
		if(instance == null) {
					
			instance =  new SingleTon();
				
		}		
		
		return instance;
		
	}

	
}

第七步:在多线程环境下,if(instance == null)可能同时成立,此时要加锁,锁的是类对象。

//第七步代码
package com.whj.offer;

public class SingleTon {

	private  static SingleTon instance; 

	private SingleTon() {
		
	}

	public static SingleTon getInstance() {
		
		if(instance == null) {

			synchronized(SingleTon.class) {
					
				instance =  new SingleTon();
									
			}
		
		}
		return instance;
		
	}

	
}

           第八步:多个线程都通过了第一个if判断,多个线程排队依次获取锁,此时如果不加以限制,仍然会创建多个对象,为了避免这种情况的发生,需要再加一个if判断,做到双重验证。

//第八步代码
public class SingleTon {

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

	
}

完整带注释的代码:
 

public class SingleTon {

	/**
	 * 第四步:创建instance
	 * 第六步:由于instance方法需要被静态方法getInstance()调用,非静态变量不能被静态变量调用,
	 * 所以需要在instance前加上static,又因为instance对象是static的,所以必须用private修饰,
	 * 因为如果才会用public,外部就直接可以通过类名.instance访问。
	 * 
	 */
	private  static SingleTon instance; 
	
	/**
	 * 构造方法无返回值,默认返回的是类的引用
	 * 第一步:把构造方法私有化,使得其他类不能实例化这个类的对象,这时Test中会报错
	 * 为了让外部获得此类的实例对象,我们可以对外提供一个获取对象的方法getInstance()
	 * 
	 **/
	private SingleTon() {
		
	}
	
	/**
	 * 第二步,创建获取对象的方法发getInstance()
	 * 第三步骤增加对象是否已经创建的判断,为了完成该步骤,创建一个全局变量instance
	 * 第五步外部调用getInstance方法需要通过对象.getInstance()方式调用,但是因为类的构造
	 * 器被私有了,不能创建对象,所以在getInstance方法前面加上static.
	 */
	public static SingleTon getInstance() {
		
		if(instance == null) {
			/**
			 * 第七步在多线程环境下,if可能同时成立,此时要加锁,锁的是类对象
			 */
			synchronized(SingleTon.class) {
				/**
				 * 判断第一个if都通过的多个线程在此排队依次获取锁,如果不加以限制,
				 * 会创建多个对象,为了避免这种情况的发生,需要再加一个if判断,做到双重
				 * 验证
				 */
				if(instance == null) {
					
					instance =  new SingleTon();
				
				}		
			}
		
		}
		return instance;
		
	}

	
}

猜你喜欢

转载自blog.csdn.net/Hanoch_wang/article/details/90645836