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方法性能较高,但是无法进行懒加载。
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; } }
原文:https://www.cnblogs.com/xiaobaituyun/p/10821565.html