设计模式(一)单例模式:2-懒汉模式(Lazy)

思想:

 

  相比于饿汉模式,懒汉模式实际中的应用更多,因为在系统中,“被用到时再初始化”是更佳的解决方案。

  设计思想与饿汉模式类似,同样是持有一个自身的引用,只是将 new 的动作延迟到 getinstance() 方法中执行。

 

public final class LazySingleton {

    private static LazySingleton instance;

    private LazySingleton() {
        if (instance != null) {
            throw new IllegalStateException();
        }
    }

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

 

  • 反射能否打破单例?

  对于 LazySingleton,这是个很有趣的问题,虽然我们在私有构造器中增加了 instance==null 的判断,但是由于延迟加载的原因,使得它无法完美地规避反射的入侵。

  这涉及到了反射入侵和 getInstance() 方法调用顺序的问题。

  如果在调用 getInstance() 方法之前进行反射入侵,那么就会打破单例,反之,可以保证单例。

public class LazySingletonTest {

    @Test
    public void testReflectSuccess() throws Exception {
        Constructor<?> constructor = LazySingleton1.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        LazySingleton1 singleton1 = (LazySingleton1) constructor.newInstance();
        LazySingleton1 singleton2 = LazySingleton1.getInstance();
        Assert.assertNotSame(singleton1, singleton2);
    }

    @Test
    public void testReflectFailure() throws Exception {
        LazySingleton1 singleton1 = LazySingleton1.getInstance();
        Constructor<?> constructor = LazySingleton1.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        try {
            LazySingleton1 singleton2 = (LazySingleton1) constructor.newInstance();
            Assert.fail();
        } catch (Exception e) {
            // Do nothing, test pass
        }
    }
}

 

  • 为什么是 synchronized 方法?

  因为是延迟加载,考虑到多线程情况,需要对方法同步。

 

  • 同步方法带来的性能问题?

  可以使用 synchronized 代码块 + Double-check Locking + volatile 关键字,对 LazySingleton 进行深一步优化,详情见:第003弹:懒汉型单例模式的演变

 
  •  优势?劣势?

  优势:延迟加载。

  劣势:不能完全屏蔽反射入侵,而且代码较为繁琐。

 

posted @ 2017-09-10 16:48  Gerrard_Feng  阅读(1673)  评论(0编辑  收藏  举报