单例模式漫谈

2017-10-25  本文已影响0人  成虫_62d0

单例模式

单例模式属于创建型模式,是Gangs of Four Design patterns中其中的一种。单例模式的实现有多种方式,很多实现方式在开发者中也是比较有争议的。本文就单例模式的应用场景,实现方式,最佳实践做一些浅显的讨论。

java singleton

单例模式确保在虚拟机中只实例化一个对象,该singleton class要提供一个对此实例的全局访问点。单例模式一般用来实现日志,缓存,线程池等。

单例模式uml类图

java singleton patten

java单例模式的实现由多种方式,但是所有的实现方式都遵循以下几个概念

下面我们来讨论单例模式的几种实现方式以及实现中的一些设计理念

public class LazySingleton {
    private static LazySingleton INSTANCE;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if (INSTANCE == null){
            INSTANCE = new LazySingleton();
        }
        return INSTANCE;
    }
}

懒汉式在我们需要使用实例的时候它才初始化,这样就没有饥饿式和静态块方式的弊端,但是会有线程安全的问题。

public class StaticBlockSingleton {

    private static  StaticBlockSingleton INSTANCE;

    static {
        try {
            INSTANCE = new StaticBlockSingleton();
        } catch (Exception e) {
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
    }

    private StaticBlockSingleton(){}

    public static StaticBlockSingleton getInstance(){
        return INSTANCE;
    }
}

静态块方式和饥饿式比较类似

public class SynchronizedSingleton {

    private static SynchronizedSingleton INSTANCE;

    private SynchronizedSingleton(){}

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

在访问该实例的静态方法前加上synchronized关键字就可以保证线程安全,但是这样的方式会让计算机付出一些额外的代价,从而影响了程序性能。为了尽量在不影响性能的情况下实现线程安全的单例模式,double checked locking方式就出现了,在这种方式下,synchronize块在方法内的if条件中使用,且使用了俩个if条件检查实例是否为null,确保只有一个实例被创建。代码如下

public class DoubleCheckSingleton {
    private static DoubleCheckSingleton INSTANCE;

    private DoubleCheckSingleton(){}

    public static DoubleCheckSingleton getInstance(){
        if (instance == null){
            synchronized (DoubleCheckSingleton.class){
                if (INSTANCE == null){
                    INSTANCE = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

反射能破坏以上所有的实现方式,其能确保获取到不同的实例。测试代码如下

public class ReflectionSingletonTest {
    public static void main(String[] args) {
        EagerSingleton eagerSingleton = EagerSingleton.getInstance();
        System.out.println(eagerSingleton.hashCode());


        Constructor [] constructors = EagerSingleton.class.getDeclaredConstructors();
        Arrays.asList(constructors).forEach(constructor -> {
            constructor.setAccessible(true);
            try {
                EagerSingleton anotherEagerSingleton = (EagerSingleton) constructor.newInstance();
                System.out.println(anotherEagerSingleton.hashCode());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        });

    }
}

运行结果如下

356573597
1747585824

单例模式线程安全的分析与测试

android中单例模式引起的内存泄漏

Java Singleton Design Pattern Best Practices with Examples

上一篇 下一篇

猜你喜欢

热点阅读