设计模式(二)--单例模式
public class Singleton { private final static Singleton instance = new Singleton(); private Singleton(){ } public static Singleton getInstance() { return instance; } }
将实例设置为static,保证只被加载一次,构造器私有化,时间上首先将实例加载,所以是恶汉模式。
恶汉模式二:不推荐
public class Singleton { private static final Singleton instance; static { instance = new Singleton(); } private Singleton(){ } public Singleton getInstance() { return instance; } }
public class Singleton { private static Singleton instance; private Singleton(){ } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
懒汉模式用时间换内存空间,直到使用的时候才会加载,但是他是线程不安全的,if(instance == null)的判断在多线程场景下同时进入,然后会创建多个实例,那样就不是单例了,所以,需要保证同步,也就是下一种方式。
public class Singleton { private static Singleton instance; private Singleton(){ } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
通过synchronized关键字修饰static方法,现在可以保证原子性,同一时间,只有一个线程进入方法,是线程安全的。但是带来的效率问题,只有一个线程进入方法,其他线程都是Blocked状态,所以不推荐使用,有点太粗暴了。
懒汉模式三:不安全
public class Singleton { private static Singleton instance; private Singleton(){ } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { instance = new Singleton(); } } return instance; } }
这样的写法应该一下就发现问题了,虽然用同步块保证同一时间创建实例的时候只有一个线程,但是已经进入了判断,还是会创建多个线程。
双重检查:推荐
public class Singleton { //需要volatile修饰,以此保证可见性和有序性 private static volatile Singleton instance; private Singleton(){ } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
上一种方法说了会创建多个实例,所以在同步块内部加了非空判断,也就是双重检查,保证只有一个实例。如果只是这样,还忽略一个问题,就是instance = new Singleton();不是一个原子性操作,实际上有三个步骤:
1.给对象分配内存
2.调用构造函数初始化成员变量
3.将对象赋值给instance
这时候可能发生CPU乱序执行,可能是1-3-2的步骤,只要执行第三部,instance就不是null了,然后其他线程直接返回instance,但此时没有进行初始化,变量都未被赋值的,很有可能出现问题,所以需要用volatile修饰。
优点:
1.线程安全
2.延迟加载
3.效率较高
public class Singleton { private Singleton(){ } private static class Inner{ private final static Singleton instance = new Singleton(); } public static Singleton getInstance() { return Inner.instance; } }
这种也是懒汉模式,只有需要的时候,才会进行初始化,而且静态内部类保证线程安全。
枚举实现:最优
public enum Singleton { INSTANCE; }
枚举实现方式,超级简单,调用只需要Singleton.INSTANCE就是实例了,进而进行其他操作处理。Joshua Bloch在《Effective Java》说过:枚举就是实现单例的最佳方式。枚举实例上是final class,继承枚举父类,其方法都是static方法。