設計模式(一)單例模式:2-懶漢模式(Lazy)

思想:html

 

  相比於餓漢模式,懶漢模式實際中的應用更多,由於在系統中,「被用到時再初始化」是更佳的解決方案。多線程

  設計思想與餓漢模式相似,一樣是持有一個自身的引用,只是將 new 的動做延遲到 getinstance() 方法中執行。post

 

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() 方法以前進行反射入侵,那麼就會打破單例,反之,能夠保證單例。url

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 方法?

  由於是延遲加載,考慮到多線程狀況,須要對方法同步。spa

 

  • 同步方法帶來的性能問題?

  可使用 synchronized 代碼塊 + Double-check Locking + volatile 關鍵字,對 LazySingleton 進行深一步優化,詳情見:第003彈:懶漢型單例模式的演變線程

 
  •  優點?劣勢?

  優點:延遲加載。設計

  劣勢:不能徹底屏蔽反射入侵,並且代碼較爲繁瑣。code

相關文章
相關標籤/搜索