单例模式
单例模式是一种常见的设计模式,它提供了一种在多线程情况下保证实例的唯一性方案。单例模式有以下几个特点:
1)单例类只能有一个实例;
2)单例类必须创建自己的唯一实例;
3)单例类必须给其他所有对象提供这一实例。
单例模式确保某个类只能有一个且必须创建自己的唯一实例,并把这个唯一实例提供给整个系统。比如在计算机系统中,线程池、打印机、对话框等常被设计成单例,计算机上有很多的通信端口,我们必须保证一个端口只能被一个请求同时调用,否则会出现混乱。
1、饿汉式
// 加final不允许被继承。
public final class SingletonHungry {
// 实例变量。
private byte[] data = new byte[1024];
// 在定义实例对象时直接初始化。
private static SingletonHungry instance = new SingletonHungry();
// 私有构造函数,不允许外部调用。
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return instance;
}
}
饿汉式的关键在于instance作为类变量并直接得到了初始化。在类初始化的过程中会被收集进()方法中,该方法能够保证百分百保证同步,这样只要一主动使用singleton类,就会直接完成创建,其中的实例变量也会得到初始化,而不能被再次实例化。
由于getInstance方法无法进行懒加载,如果一个类中的成员属性比较少,占用的内存资源较少,饿汉式是适用的。但当成员较多时,就变得不适用了。
2、懒汉式
public final class SingletonLazy {
// 实例变量。
private byte[] data = new byte[1024];
// 定义实例,不直接初始化。
private static SingletonLazy instance = null;
private SingletonLazy(){
}
public static SingletonLazy getInstance() {
if(instance == null) instance = new SingletonLazy();
return instance;
}
}
懒汉式就是在使用类的实例的时候再去创建。但由于在SingletonLazy.class被初始化时instance没有被实例化,而是在getInstance方法中先判断它是否被实例化而再去创建实例,这会导致在多线程的情况下,如果多个线程都看到了instance==null,那么instance很可能会被实例化多此,而不能保证单例的唯一性。
3、懒汉式+同步方法
public final class SingletonLazySyn {
// 实例变量。
private byte[] data = new byte[1024];
private static SingletonLazySyn instance = null;
private SingletonLazySyn() {
}
// 加synchronized同步控制,每次只能有一个线程执行。
public static synchronized SingletonLazySyn getInstance() {
if(null == instance) instance = new SingletonLazySyn();
return instance;
}
}
懒汉式+同步方法既满足懒加载又绝对保证instance实例的唯一性,但是阻塞的方式会导致性能低下。
4、枚举方式
使用枚举方式实现单例模式是《Effective Java》作者力推的方式。
枚举类型不允许被继承,线程安全且保证实例唯一性。对Singleton主动使用,INSTANCE会立即实例化。
// enum本身是final的,不允许被继承。
public enum SingletonEnum {
INSTANCE;
// 实例变量。
private byte[] data = new byte[1024];
SingletonEnum() {
}
public static void method() {
// 调用此方法,则是主动使用SingletonEnum,INSTANCE将会被实例化。
}
public static SingletonEnum getInstance() {
return INSTANCE;
}
}
增加懒加载特性:
public class SingletonEnumLazy {
// 实例变量。
private byte[] data = new byte[1024];
private SingletonEnumLazy() {
}
public static SingletonEnumLazy getInstance() {
return EnumHolder.INSTANCE.getInstance();
}
// 使用枚举。
private enum EnumHolder{
INSTANCE;
private SingletonEnumLazy instance;
EnumHolder() {
this.instance = new SingletonEnumLazy();
}
private SingletonEnumLazy getInstance() {
return instance;
}
}
}
另外还有Double-Check、volatile+Double-Check、Holder等实现方式,后续补充。
参考书籍《Java高并发编程详解》。