线程安全的单例模式的常用四种创建方式

单例模式是常用的一种设计模式,线程安全的单例模式一般有三种写法,其中双重检查模式是最复杂的,也是不推荐的。
那有没有更好的推荐方式呢?答案是肯定的。请继续往下看。

1. 不使用同步锁

饱汉式

public class Singleton {

    //直接初始化
    private static Singleton instance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}

优点:这种方式的性能是非常好的,只是简单返回instance,没有做其他任何锁操作,所以在并行程序中,会有良好表现。
缺点:但是有点明显的不足之处是 Singleton 实例在何时被创建并不受控制,对于静态成员变量instance,会在类第一次初始化的时候被创建,但是这并不一定是getInstance() 方法第一次调用的时候。

2. 使用同步锁

懒汉式

public class Singleton {

    private static Singleton instance;

    private Singleton() {
    }

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

优点:充分利用了延迟加载,只在真正需要的时候创建对象。(只在第一次调用时创建对象)
缺点:为了防止对象被多次创建,不得不使用synchronized进行方法同步。并发环境下,竞争激烈的场合对性能可能产生一定的影响。

3. 双重检查模式

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;
    }
}

优点:这种方式在第二种的基础上做了改进,调用 getInstance() 方法的时候不需要每次都锁类对象。如果 instance 实例已经创建,则直接返回。
缺点:在JDK1.5之后才能保证正确性,比较丑陋复杂,这里不推荐,推荐如下第四种方式。

4. 利用虚拟机的类初始化机制

这里介绍下推荐使用的一种,这种方式结合了第一种不需要同步锁和第二种延迟加载的优点。

public class Singleton {

    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
    //内部静态私有化类
    private static class SingletonHolder {
        private static Singleton instance = new Singleton();
    }
}

这种方式没有锁,在高并发环境下性能更好;延迟加载,只在第一次调用时被创建。
这种方式巧妙地利用了内部类和类的初始化方式,内部类被申明为 private ,这使得我们不可能在外部访问并初始化它。只可能在 getInstance() 方法内部对 SingletonHolder 类进行初始化。

猜你喜欢

转载自blog.csdn.net/iluojie/article/details/79950873