最详细的单例模式

单例模式:在整个项目中,只产生一个实例化对象,这类主要由数据库连接池等,对于这类对象,一定要小心使用, 因为一般而言单例对象在整个项目中存活很久。有甚者贯穿了这个项目生命周期。定义全局的集合的时候,一定要小心集合内的元素,有可能存储在集合的对象在程序中没有作用,但在集合内存在强引用而造成内存泄漏。

下面就来介绍几种单例模式的写法。

饿汉式

/**
 * 饿汉式:在类加载期间就完成单例对象的绑定。由于在类加载期间是线程安全的,所以饿汉式是不会发生线程安全问题的。
 */
class SigletonObject{
	public static SigletonObject sigletonObject = new SigletonObject();
	private SigletonObject() {}
	public static SigletonObject getInstance() {
		return sigletonObject;
	}
}

懒汉式

再不是并发场景下,懒汉式

class SigletonObject{
	public static SigletonObject sigletonObject = null;
	private SigletonObject() {}
	public static SigletonObject getInstance() {
		if (sigletonObject == null) {
			sigletonObject = new SigletonObject();
		}
		return sigletonObject;
	}
}

但是上面这段代码在多线程环境下,就可能产生多个对象,这对于单例模式是不可忍受的。

class SigletonObject{
	public static SigletonObject sigletonObject = null;
	private SigletonObject() {}
	public static synchronized SigletonObject getInstance() {
		if(sigletonObject == null) {
			sigletonObject = new SigletonObject();
		}
		return sigletonObject;
	}
}

双重锁

这段代码虽然是线程安全,但即使对象已经创建成功,获取该对象都要获取锁,这是不能忍的的。

class SigletonObject {
	public static SigletonObject sigletonObject = null;

	private SigletonObject() {
	}

	public static SigletonObject getInstance() {
		if (sigletonObject == null) {
			synchronized (SigletonObject.class) {
				if (sigletonObject == null) {
					sigletonObject = new SigletonObject();
				}
			}
		}
		return sigletonObject;
	}
}

双重锁判断,不管你的并发度多高,他都能满足要求,但是同样,他是有可能暴露出还没初始化完成的对象,这是不能忍的。

而造成这个问题的是一般在对象生成的中,首先是分配地址,初始化对象,这是没问题的,但是把初始化的对象地址赋给sigletonObject和初始化对象存在指令重排序问题,这就会造成把没有初始化对象给sigletonObject,这就会造成问题。

class SigletonObject {
	public static volatile SigletonObject sigletonObject = null;

	private SigletonObject() {
	}

	public static SigletonObject getInstance() {
		if (sigletonObject == null) {
			synchronized (SigletonObject.class) {
				if (sigletonObject == null) {
					sigletonObject = new SigletonObject();
				}
			}
		}
		return sigletonObject;
	}
}

这段代码就完美了。

静态内部类

class SigletonObject{
        private SigletonObject() {}
	static class inner{
		private static SigletonObject sigletonObject = new SigletonObject();
	}
	public static SigletonObject getInstance() {
		return inner.sigletonObject;
	}
}

在加载SigletonObject类时,不会加载其内部类,只有调用inner.sigletonObject才会真正加载内部类,这就可以满足懒加载,这也是作者推荐使用的。但是他也有不适合的场景,虽然我们私有化了他们的构造函数,但是如果是通过反射获取对象的话,这就会造成产生多个对象,所以如果项目需要通过反射获取单例对象,就不适用了。

枚举

class SigletonObject{
	private SigletonObject() {}
	private enum SigletonEnum{
		INSTANCE;
		private SigletonObject sigletonObject;
		private SigletonEnum() {
			this.sigletonObject = new SigletonObject();
		}
		public SigletonObject getInstance() {
			return sigletonObject;
		}
	}
	public static SigletonObject getInstance() {
		return SigletonEnum.INSTANCE.getInstance();
	}
}

如果说有一种让作者都心服口服的,那就是枚举实现单例模式,虽然枚举现在很少使用,但确实是好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值