java_单例模式

日期:2018-09-16       浏览:482

一 为什么用单例模式

单例模式是设计模式中使用最为普便的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。在java中,这样的行为能带来量大好处:
  1. 对于频繁使用的对象,可以省略new操作花费的时间;
  2. 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻gc压力,缩短gc停顿时间;

二 单例模式的实现方式

2.1 饿汉模式

public class Singleton {

    private Singleton() {
        System.out.println("Singleton is create .");
    }

    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
}
使用以上模式需要特别注意的几点:
  1. Singleton 的构造函数设置为 private,告诉开发人员不可随便创建这个类的实例;
  2. instance 对象必须是private 并且是 static 的;如果不是 private,那么instance 的安全性无法保证;因为工厂方法 getInstance() 是 static 的,因此对应的 instance 也必须是 static的;
这个模式的性能是非常好的,因为 getInstance 方法只是简单的返回 instance,并没有任何锁操作。但是这种方式有一点明显的不足,就是Singleton 实例在什么时候创建是不受控制的。对于静态成员 instance,它会在类第一次初始化的时候被创建,这个时刻并不一定是 getInstance 方法第一次被调用的时候。
例如:
public class Singleton {

    private Singleton() {
        System.out.println("Singleton is create .");
    }

    // 静态属性,类第一次调用该属性时,类实例对象也会被创建
    public static String NAME = "Singleton";

    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    public static void main(String[] args) {
        System.out.println(Singleton.NAME);
    }
}
注意在类中存在一个静态成员属性 NAME ,在任何地方调用用 name 时都会导致 instance 实例被创建。任何对 Singleton 方法或字段的引用,都会导致类初始化,并创建实例,但是类初始化只有一次,因此instance 实例永远只会被创建一次。
异常 main 函数输出结果如下:
Singleton is create .
Singleton

2.2 同步加锁模式(懒汉模式)

如果你想精确控制 instance 的创建时间,那么第一种模式就不太友好了。我们可以使用懒汉模式。
public class Singleton {

    private Singleton() {
        System.out.println("Singleton is create .");
    }

    private static Singleton instance = null;

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
这个模式的核心思想是:最初,我们并不需要实例化 instance,而当 getInstance 方法第一次被调用时,创建单例对象。为了防止对象被多次创建,我们不得不使用 synchronized 进行方法同步。
这种实现的好处是,充分使用了延迟加载,只在真正需要时创建对象。但坏处也很明显,并发环境下加锁,竞争激烈的场合对性能可能产生一定的影响。

2.3 静态内部类

以上两种单例实现中,可以说个有千秋。静态内部类模式就结合了二者的优势。
public class Singleton {

    private Singleton() {
        System.out.println("Singleton is create .");
    }

    private static class SingletonHolder {
        private static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}
上述代码实现了一个单例,并且同时拥有前两种方式的优点。首先 getInstance 方法中没有锁,这使得在高并发环境下性能优越。其次,只有在 getInstance 方法第一次被调用时 Singleton 的实例才会被创建。
内部类 SingletonHolder 被申明为 private,这使得我们不可能在外部访问并初始化它。而我们只可能在 getInstance 内部对 SingletonHolder 类进行初始化,利用虚拟机的类初始化机制创建单例。
扫码关注有惊喜

(转载本站文章请注明作者和出处 qbian)

暂无评论

Copyright 2016 qbian. All Rights Reserved.

文章目录