JobPlus知识库 IT 软件开发 文章
单例模式实现的几种方式

方式一:饿汉模式public class Singleton {        private static Singleton instance = new Singleton();        private Singleton() {    }    public static Singleton getInstance() {        return instance;    } }

在ClassLoader加载类时,实例化出一个对象,其后使用时返回该对象。

  • 优点:线程安全,代码简洁
  • 缺点:实例长期被静态成员持有,从类加载开始就一直常驻内存

方式二:懒汉模式public class Singleton {    private static Singleton instance;    private Singleton() {    }    public static Singleton getInstance() {        if (instance == null) {            instance = new Singleton();        }        return instance;    } }

在实例被使用时初始化,采用懒加载的方式,所以俗称懒汉模式

  • 优点:在使用时加载,提高资源利用率和程序的运行效率
  • 缺点:多线程场景下线程不安全

方式三:线程安全模式

饿汉模式资源利用率低,懒汉模式线程不安全,于是就有了线程安全的懒汉模式
这种模式有几种写法

代码1public class Singleton {    private static Singleton instance;    private Singleton() {    }    public synchronized static Singleton getInstance() {        if (instance == null) {            instance = new Singleton();        }        return instance;    } }代码2public class Singleton {    private static Singleton instance;    private Singleton() {    }    public static Singleton getInstance() {        synchronized (Singleton.class) {            if (instance == null) {                instance = new Singleton();            }        }        return instance;    } }代码3public class Singleton {    private static Singleton instance;    private Singleton() {    }    public static Singleton getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                instance = new Singleton();            }        }        return instance;    } }

代码1和代码2,本质上是一样的,现货区类的class对象同步锁,然后判断对象是否为空,为空则实例化对象,随后返回对象,这两种模式是可以实现线程安全的,缺点是,每次调用getInstance()获取对象,都要活动类的class对象的同步对象锁;至于代码3,是不能实习线程安全的,因为在判空阶段没有使用同步代码块,对象还是有可能会重复创建。

综合代码1、2、3,得出以下实现方式:

代码4:public class Singleton {    private static Singleton instance;    private Singleton() {    }    public static Singleton getInstance() {        if (instance == null) {//第一次校验,如果不对象为空,直接返回,不必获取同步对象锁            synchronized (Singleton.class) {                if (instance == null) {//第二次校验,获取同步对象锁之后再去检验                    instance = new Singleton();                }            }        }        return instance;    } }

在获取类的class同步对象前后,各做一次判断,有效防止对象多次创建。这种方式仍然是不稳定的,jdk1.5之后引入了volatile关键字。

代码5:双重校验锁式public class Singleton {    private static volatile Singleton instance;//这里使用了volatile关键字    private Singleton() {    }    public static Singleton getInstance() {        if (instance == null) {//第一次校验,如果不对象为空,直接返回,不必获取同步对象锁            synchronized (Singleton.class) {                if (instance == null) {//第二次校验,获取同步对象锁之后再去检验                    instance = new Singleton();                }            }        }        return instance;    } }

volatile让变量每次在使用的时候,都从主存中取。而不是从各个线程的“工作内存”。也就是说,volatile变量对于每次使用,线程都能得到当前volatile变量的最新值。
这种方式一般称为双重校验锁式,也是我最喜欢使用的一种方式。

  • 优点:线程安全,实现懒加载,资源利用利用率和运行效率较高
  • 缺点:代码量稍微大了些,jdk1.5之前不稳定

方式四:静态内部类式public class Singleton {    private Singleton() {    }    public static Singleton getInstance() {        return InnerStaticClass.singleton;    }    private static class InnerStaticClass {        private static Singleton singleton = new Singleton();    } }

这里先补充下类加载的相关知识,内部类跟外部类不是同时加载的,是在内部类第一次被使用时加载
这种方式和饿汉模式一样是利用了Java的类加载器,保证了实例唯一,同事有保证了又保留了懒汉模式的懒加载特性。

  • 优点:线程安全,实现懒加载,资源利用利用率和运行效率较高
  • 缺点:多写了一个类

特殊:枚举实现单例public enum Singleton {    Instance;//只有一个成员    public  void set(){    } }

当枚举只有只有一个成员时,这个成员就是它的唯一实例,这样使用

Singleton.Instance.set();


如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏支持
164人赞 举报
分享到
用户评价(0)

暂无评价,你也可以发布评价哦:)

扫码APP

扫描使用APP

扫码使用

扫描使用小程序