Java单例模式的七种实现
1.饿汉式
//final不允许类被继承
public final class Singleton {
//实例化变量
private byte[] data=new byte[1024];
//直接初始化
private static Singleton instance=new Singleton();
//私有构造函数,不允许外部new
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
如果主动使用Singleton类,instance实例将直接完成创建,包括其中的实例变量都会得到初始化,但是instance可能被加载很长一段时间后才被使用,instance实例开辟的堆内存会驻留更久的时间,如果说一个类的成员变量不多,且占用内存资源较少,可以使用饿汉式,总结它可以保证多个线程下唯一实例,getInstance方法性能较高,但是无法进行懒加载。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。2.懒汉式
//final不允许类被继承
public final class Singleton {
//实例化变量
private byte[] data=new byte[1024];
private static Singleton instance=null;
//私有构造函数,不允许外部new
private Singleton(){
}
//等到需要使用时进行创建
public static Singleton getInstance(){
if (instance==null){
instance=new Singleton();
}
return instance;
}
}
该方法在多线程环境下不能保证单例的唯一性。
3.懒汉+同步方法
//final不允许类被继承
public final class Singleton {
//实例化变量
private byte[] data=new byte[1024];
private static Singleton instance=null;
//私有构造函数,不允许外部new
private Singleton(){
}
//等到需要使用时进行创建
public static synchronized Singleton getInstance(){
if (instance==null){
instance=new Singleton();
}
return instance;
}
}
可以保证在多线程环境下单例的唯一性,但是synchronied关键字会导致在同一时刻方法只能被一个线程所访问,性能低下。
4.双重锁检查
//final不允许类被继承
public final class Singleton {
//实例化变量
private byte[] data=new byte[1024];
private static Singleton instance=null;
//私有构造函数,不允许外部new
private Singleton(){
}
//等到需要使用时进行创建
public static Singleton getInstance(){
if (instance==null){
synchronized (Singleton.class){
if (instance==null) instance=new Singleton();
}
}
return instance;
}
}
这段代码看起来很完美,很可惜,它是有问题。主要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情:
1.给 instance 分配内存
2.调用 Singleton 的构造函数来初始化成员变量
3.将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。
5.volatile+双重锁检查
//final不允许类被继承
public final class Singleton {
//实例化变量
private byte[] data=new byte[1024];
//禁止指令重排序
private volatile static Singleton instance=null;
//私有构造函数,不允许外部new
private Singleton(){
}
//等到需要使用时进行创建
public static Singleton getInstance(){
if (instance==null){
synchronized (Singleton.class){
if (instance==null) instance=new Singleton();
}
}
return instance;
}
}
加上volatile禁止了指令的重排许操作。满足多线程下的单例,懒加载,获取实例的高效性。
6.Holder方式
//final不允许类被继承
public final class Singleton {
//实例化变量
private byte[] data=new byte[1024];
//私有构造函数,不允许外部new
private Singleton(){
}
//在静态内部类中持有singleton的实例,可以被直接初始化
private static class Holder{
private static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return Holder.instance;
}
}
Holder类中定义了Singleton的静态变量,并且直接进行了实例化,当Holder被主动引用的时候会创建Singleton实例。Holder方式的单例模式是最好的设计之一,也是目前用的比较广泛的设计之一。
7.枚举方式
枚举类型不允许被继承,同样是线程安全的且只能被实例化一次,但是枚举类型不能够懒加载,对Singleton主动使用,比如调用其中的静态方法则INSTANCE会立即得到实例化。
public enum Singleton{
INSTANCE;
private byte[] data=new byte[1024];
Singleton(){
System.out.println("INSTANCE will be initialized immediately");
}
public static void method(){
//调用该方法会主动使用Singleton,INSTANCE实例将会被实例化
}
public static Singleton getInstance(){
return INSTANCE;
}
}

