栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式之单例模式,看这篇文章就够了

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式之单例模式,看这篇文章就够了

单例模式是23种设计模式中最简单、最常见的设计模式之一,许多人学习设计模式,第一个接触到的就是单例模式。

单例模式属于创建型模式,其目的是在当前进程中只创建一个实例,也可能是一个线程中属于单例。

想要写出安全又简洁的单例模式,如果不注意细节,很容易有潜在的bug,本文总结了最常见的4种单例模式写法,并分析每种优缺点。

懒汉模式

懒汉模式,就是在用的时候才会被创建,体现的是一种延迟加载的思想。

public class Singleton {      private static Singleton instance;      private Singleton (){}      public static Singleton getInstance() {          if (instance == null) {              instance = new Singleton();          }        return instance;      }  }  

这种写法lazy loading很明显,但是致命的是在多线程环境下不能正常工作,再来看看并发安全的懒汉模式。

public class Singleton {      private static Singleton instance;      private Singleton (){}      public static synchronized Singleton getInstance() {          if (instance == null) {              instance = new Singleton();          }          return instance;      }  }  

这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是synchronized加锁之后,每次获取单例都需要上锁,所以效率很低,99%情况下不需要同步。再看下它的优化版:

public class Singleton {      private volatile static Singleton singleton;      private Singleton () {}      public static Singleton getSingleton() {          if (singleton == null) {              synchronized (Singleton.class) {                  if (singleton == null) {                      singleton = new Singleton();                  }            }        }        return singleton;      }  }  

这就是大名鼎鼎的双重检查锁方式,也有人质疑这种单例模式的可靠性,这里笔者不做过多讲解,有兴趣的伙伴可以去网上搜索:double-checked locking is broken。

需要注意的是,singleton实例变量必须加volatile关键字。加volatile,这里主要使用了它的有序性特性,可以禁止指令重排。有许多的博客作者说是利用了volatile的可见性,并不是的。

singleton = new Singleton();

是由三个步骤组成的:

  1. 为对象分配内存

  2. 实例化对象

  3. 将引用指向对应的内存地址


第2,3步可能发生指令重排列,第一个线程先将singleton指向一个未实例化对象的内存地址,然后再进行实例化对象。


若此时第二个线程进行第一个非空判断时,则为false,会直接返回还没有实例化对象的内存地址,从而可能产生空指针异常。

饿汉模式

饿汉模式就是在使用前,实力已经被创建了。其实现代码如下:

public class Singleton {      private static Singleton instance = new Singleton();      private Singleton (){}      public static Singleton getInstance() {          return instance;      }  }  

这种方式基于classloder机制避免了多线程的同步问题,instance在类装载时就实例化,显然没有达到lazy loading的效果,也有变种写法。​​​​​​​

public class Singleton {      private Singleton instance = null;      static {          instance = new Singleton();      }      private Singleton () {}    public static Singleton getInstance() {      return this.instance;      }  }  

静态内部类

这是我在代码中比较常用的一种写法。​​​​​​​

public class Singleton {    private static class SingletonHolder {        private SingletonHolder() {}        private static final Singleton INSTANCE = new Singleton();        public static final Singleton getInstance() {            return INSTANCE;        }    }    public static Singleton getSingleton() {        return SingletonHolder.getInstance();    }}

或者:

public class Singleton2 {    private Singleton2() {}    private static final class Singleton2Holder {        public static final Singleton2 INSTANCE = new Singleton2();    }    public static Singleton2 getInstance() {        return Singleton2Holder.INSTANCE;    }}

这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,

这种方式与饿汉模式不同的是,是Singleton类被装载了,instance不一定被初始化,有lazy loading效果。

枚举

枚举和静态代码块的特性相似,使用枚举时,构造方法会被自动调用,也可以利用这个特性实现单例模式,不过比较少见。​​​​​​​

public class EnumSingleton{    private EnumSingleton(){}    public static EnumSingleton getInstance(){        return Singleton.INSTANCE.getInstance();    }        private static enum Singleton{        INSTANCE;                private EnumSingleton singleton;        //JVM会保证此方法绝对只调用一次        private Singleton(){            singleton = new EnumSingleton();        }        public EnumSingleton getInstance(){            return singleton;        }    }}
public static void main(String[] args) {    EnumSingleton obj1 = EnumSingleton.getInstance();    EnumSingleton obj2 = EnumSingleton.getInstance();    System.out.println("obj1==obj2?" + (obj1==obj2));  // true}

总结:

单例模式主要有懒汉模式、饿汉模式、内部类、基于枚举,4种写法,基于内部类的方式比较常见,也是比较推荐的方式。

设计模式单纯的使用比较简单,在许多复杂的业务场景,常常会把多种模式混合起来使用,比如单例模式+工厂模式。而且重要的是融会贯通,不在于死记硬背,这样才能灵活多变的应用。

END

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/272183.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号