单例模式

单例模式是一种非常常见的设计模式, 在应用这个模式时,单例对象的类必须保证只有一个实例存在。 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
通俗来说就是一个类只有一个实例,并且由类自行实例化。
单例设计模式的核心思想:

	1.构造器私有化
	2.提供一个静态变量用于保存对象实例
	3.提供一个外部访问对象的方式

其中对于步骤3,莫过于两种方式,静态变量公有化或者提供一个获取对象的方法,对于这两种不同的方式也就衍生出了饿汉式和懒汉式,饿汉式和懒汉式的区别在于创建实例化的时期,由此导致的线程安全方面的不同。

饿汉式(积极创建,线程安全)

顾名思意,一调用该类时便不管三七二十一直接创建实例,不管能不能用上。显然,在类加载时期便完成了对象的创建。此后所有调用者调用的都是已经创建好的这个实例,定然不会出现线程安全问题。
以下来说说饿汉式的具体实现。(直接公有化变量)
第一种方式:直接公有化变量。

	public class Singleton1 {
	
	//2.提供静态变量保存创建的实例;3.变量公有化可直接访问。
	public static Singleton1 INSTANCE = new Singleton1();
	
	//1.构造器私有化
	private Singleton1() {
		
	}
}

第二种方式:枚举实现

	public enum Singleton2 {
	INSTANCE
}

第三种方式:通过静态代码块加载实现。(适合于创建复杂对象,当创建对象需要读取配置文件时可用这种方式)

public class Singleton3 {
	
	public static Singleton3 INSTANCE;
	
	private Singleton3(String info) {
		
	}
	
	static {
		Properties prop = new Properties();
		try {
			prop.load(Singleton3.class.getClassLoader().getResourceAsStream("aa.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		INSTANCE = new Singleton3(prop.getProperty("info"));
	}
}

总结:饿汉式在类加载时期完成对象的创建,是线程安全的。

懒汉式(延时创建,线程不安全)

顾名思意:在使用类时不会直接创建,只有在具体的发出对象调用请求(使用获取对象的方法)时才进行创建。
具体实现如下:

	public class Singleton4 {
	//2.提供静态变量保存实例对象
	private static Singleton4 instance;
	
	//1.构造器私有化
	private Singleton4() {
		
	}
	//3.对外提供获取对象的方法
	public static Singleton4  getInstance(){
		 if(instance == null) {
			 instance = new Singleton4();
		 }
		 return instance;
	}
}

很显然,改代码是存在线程安全问题的。在多线程情况下,当instance为空时,可能会有多个线程通过if(instance == null),导致创建出多个对象。
线程安全版本1:(通过加锁实现,DCL(Double Check Lock)+volatile)

 public class Singleton5 {
	
	private static volatile Singleton4 instance;
	
	
	private Singleton5() {
		
	}
	
	public static Singleton5 getInstance(){
		if(instance == null){
    		synchronized(Singleton5.class){
	    		 if(instance == null) {
	    			 instance = new Singleton4();
	    		 }
    		 }
		 }
		 return instance;
	}
}
//说明:1.为什么要加DCL,同步锁外判断,为避免在实例已经创建的情况下每次获取实例都加锁取,影响性能;
锁内判断,考虑多线程情况下,两个以上线程都已经运行至同步锁处,也就是都已经判断变量为空,如锁内不再次判			
断,会导致实例重复创建。
		2.为什么要加volatile,instance = new Singleton4()这句话由三条字节码指令完成,
			其具体步骤:1.分配内存空间,2.初始化,3.对引用赋值。由于指令重排序的存在,这三个步骤可能并不是按
			顺序执行。加volatile能够避免指令重排序。

线程安全版本2:通过内部类实现

public class Singleton6 {
	
	private Singleton6() {
		
	}
	
	//说明:外部类的加载不会导致内部类的加载。
	private static class Inner{
		private static Singleton6 instance = new Singleton6();
	}
	
	//在调用该方法时才会导致内部类的加载。
	public static Singleton6 getInstance() {
		return Inner.instance;
	}
}

总结:懒汉式不会在加载类时创建实例对象,会在发出对象调用请求时才进行实例化。可能会导致线程安全问题,通过加锁和内部类可解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值