本文介绍了单例设计模式的饿汉式、懒汉式、双重锁、静态内存写法。
一、饿汉式
public class SingleTon { // 1.私有化构造方法 private SingleTon() {} // 2.私有的静态的当前类属性 private static SingleTon instance = new SingleTon(); // 3.公共的获取当前类属性的方法 public static SingleTon getInstance() { return instance; }}
优点:不会出现第一次使用对象时,出现延迟的情况,响应速度快,线程安全。
缺点:不管单例对象是否被使用,只要类一加载就创建,增加了内存的压力。
二、懒汉式
public class SingleTon { // 1.私有构造方法 private SingleTon() {} // 2.私有的静态的当前类类型的属性 private volatile static SingleTon instance; // 3.公共的静态的获取当前类对象的方法 public static SingleTon getInstance() { if(null == instance) { instance = new SingleTon(); } return instance; }}
优点:对象需要使用时才创建,减轻了内存的压力。
缺点:第一次使用单例对象时,会出现一点延迟,线程非安全。
三、双重判断(懒汉式的升级版)
public class SingleTon { // 1.私有构造方法 private SingleTon() {} // 2.私有的静态的当前类类型的属性 private static volatile SingleTon instance; // 3.公共的静态的获取当前类对象的方法 public static SingleTon getInstance() { // 双重校验的目的在于提高方法的执行效率 if(null == instance) { synchronized (SingleTon.class) { if(null == instance) { instance = new SingleTon(); } } } return instance; }}
volatile关键字的作用:防止创建单例对象指令的重排序,创建对象可以分为三步步骤:①开辟一块堆内存空间②创建对象③将堆内存地址赋值给栈内存中的局部变量引用。所谓的指令重排序就是①②③的执行顺序会变成①③②,这就会出现单例对象还未创建,但是局部变量已经有引用了,这时局部变量进行后续操作都是错误的。
为什么会有指令的重排序呢?
因为指令的重排序可以提高程序的执行效率,所以在JVM中默认会对指令进行重排序,而有些情况我们不希望指令进行重排序,这时就需要使用到volatile关键字来防止指令的重排序。
优点:对象需要使用时,才创建,减轻了内存的压力,线程安全。
缺点:第一次使用单例对象时,会出现一点延迟。
四、静态内部类
public class SingleTon { // 1.私有构造方法 private SingleTon() {} // 2.静态内部类 static class Inner { private static SingleTon instance = new SingleTon(); } // 3.公共的静态的获取当前类对象的方法 public static SingleTon getInstance() { return Inner.instance; }}
优点:内存压力小,线程安全,写法更加优雅。
缺点:稍稍复杂。