对于以上两种单例模式的实现,事实上通过java的反射机制是能够实例化为private的类的,那基本上会使所有的java单例的实现失效,在这里我们不考虑java的反射机制。
但是此外以上的懒汉式实现的单例模式没有考虑线程安全性问题,他是线程不安全的,并发环境下可能出现多个SingleClass的实例,要实现线程安全,有以下几种方式:
什么是线程安全?
在多线程环境下,执行同一段代码或者变量结果都是相同的,我们就称为线程安全的,反之则为非线程安全的,线程不安全的。
1.在createInstance()方法上加同步
public static synchronized SingleClass createInstance(){ if(instance == null) instance = new SingleClass(); return instance; }2.双重检查锁定
public static SingleClass createInstance(){ if(instance==null){ synchronized (SingleClass.class) { if(instance==null){ instance = new SingleClass(); } } } return instance; }3.静态内部类
class SingleClass{ private SingleClass(){} private static class Lazy{ private static final SingleClass INSTANCE = new SingleClass(); } public static final SingleClass createInstance(){ return Lazy.INSTANCE; } }这种方式要比前两种好些,即实现了线程安全,有避免了同步带来的性能影响。
1、2、3三种实现又有何区别?
第1种,在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的, 第2种,在createInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗 第3种,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗。对于饿汉式,它在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。