设计模式之单例模式

设计模式之单例模式


【生命不息,学习不止】
单例模式,顾名思义,指的就是一个类只有一个实例。本文就记录下单例模式的几种实现方法,并根据自己的学习、工作经验和理解简单介绍下各个方式的优缺点(或问题),和大家一起分享,也便于自己以后查看,如有不对,还请大家多指教。
一:饿汉式
代码如下,这是一种简单、常见的写法。

public class Singleton {

	private static final Singleton instance = new Singleton();

	private Singleton() {
	}

	public static Singleton getInstance() {
		return instance;
	}

}

此种方式的优点在于,1、简单;2、线程安全。但是也有缺点,那就是只要该类被加载,就会被实例化,即使系统永远用不上这个实例,所以会占有一定的内存。
二:懒汉式
实现方式如下

public class Singleton {

	private static Singleton instance = null;

	private Singleton() {
	}

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

}

这种方式只有等到调用了getInstance方法时才会实例化,解决了饿汉式方式类被加载就会实例化的缺点。但这也带来了另外一个问题,那就是线程安全,很明显在多线程环境下,该类很可能被实例化多次。
三:线程安全的懒汉式
代码如下,这种实现方式只是在第二种方式的基础上加上synchronized关键字,实现线程安全。

public class Singleton {

	private static Singleton instance = null;

	private Singleton() {
	}

	public static synchronized Singleton getInstance() {
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}

}

这种实现方式有个缺点,那就是每次获取实例的时候都会进行加锁,即使已经被实例化了,这明显对性能是有影响的。
四:双重检查加锁
为了解决第三种频繁加锁的问题,于是就有了第四种方式,如下

public class Singleton {

	private static volatile Singleton instance = null;

	private Singleton() {
	}

	public static Singleton getInstance() {
		if (instance == null) {// 第一重检查
			synchronized (Singleton.class) {
				if (instance == null) {// 第二重检查
					instance = new Singleton();
				}
			}
		}
		return instance;
	}

}

下面对这种方式进行两点简单介绍。
第一点:代码有两处instance为空检查,其中第一重检查是为了解决第三种方式中频繁加锁的问题,如果已经实例化了,获取实例的时候就不用再次加锁,提升性能;第二重检查目的和第三种方式一样,是为了避免实例化多次。
第二点:可能有人注意到instance用了volatile关键字修饰,简单介绍下这里的作用有两以下两个目的,具体的可以了解下volatile关键字和JVM相关知识。
1、保证变量可见性。我们知道JVM运行时,有主内存和工作内存,每个线程都有自己的工作内存,加了volatile修饰后的变量,一个线程对该变量的修改,其他线程可以及时感知到;
2、禁止指令重排序。JVM创建一个对象会分为三步,A-给对象分配内存,B-初始化对象,C-将对象引用赋值给变量,而BC两个步骤可能被重排序,也就是说执行顺序为A-C-B,如上面的代码,若没有volatile修饰,重排序后,创建对象的线程执行到步骤C,另一个线程访问了instance变量,此时instance并不为空,但是并没有初始化,这种情况下是会发生异常的。
五:静态内部类
代码如下

public class Singleton {

	private Singleton() {
	}

	public static Singleton getInstance() {
		return InnerClass.INSTANCE;
	}

	private static class InnerClass {
		static Singleton INSTANCE = new Singleton();
	}

}

可以看到这种方式还是比较简洁的,而且也是线程安全的。
六:枚举
以上介绍的五种单例模式的实现方式,都有一个缺点,不知道大家想到没有,那就是面对序列化或反射攻击时,那么就可以实例化无数个对象了,所以就有人想到了用枚举方式实现单例模式。这种方法绝对防止多次实例化,著名的《Effective Java》书中就将此称作是最佳的单例模式实现方式。

public enum Singleton {

	INSTANCE;

	public static Singleton getInstance() {
		return INSTANCE;
	}

}

看到没,代码绝对够简洁、够安全、够优雅。

好了,单例模式的创建方式就介绍到此。如果本文有哪里不对的地方,或者还有其他方式实现单例模式也可告知,欢迎指正交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值