單例模式(餓漢、懶漢)高頻面試考點
單例模式涉及到一個單一的類,該類負(fù)責(zé)創(chuàng)建自己的對象,同時確保只有單個對象被創(chuàng)建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
注意:
- 1、單例類只能有一個實例。
- 2、單例類必須自己創(chuàng)建自己的唯一實例。
- 3、單例類必須給所有其他對象提供這一實例。
餓漢模式(初始就直接創(chuàng)建好)
類加載的時候?qū)嵗齽?chuàng)建并初始化好了,所以是線程安全的。
//外界不能 new 這個類,所以用 static 來修飾字段和方法 //不允許在類外修改創(chuàng)建的實例,所以實例用 private 聲明 public class Singleton { private Singleton(){} private static Singleton singleton=new Singleton();//直接創(chuàng)建好 public static Singleton getInstance(){ return singleton; }
懶漢模式(需要時再創(chuàng)建)雙重檢測保證線程安全
singleton = new Singleton();
該語句非原子操作,實際是三個步驟。
- 1.給singleton分配內(nèi)存;
- 2.調(diào)用 Singleton 的構(gòu)造函數(shù)來初始化成員變量;
- 3.將給singleton對象指向分配的內(nèi)存空間(此時singleton才不為null);
必須使用volatile保證執(zhí)行順序,比如三個步驟重排序后為1 3 2
,這樣第一個線程初始化對象到一半,第二個線程來發(fā)現(xiàn)已經(jīng)不是null了就直接返回了 實際上該對象此時還沒有完全初始化 可能會出現(xiàn)這個問題。
synchronized
使用Singleton
類的Class對象作為鎖對象,當(dāng)多個線程同時訪問getInstance()
方法時,只有一個線程能夠進(jìn)入同步代碼塊實例化Singleton類,保證了單例的唯一性。
public class Singleton { private Singleton(){} private static volatile Singleton singleton=null; public static Singleton getInstance(){ if(singleton==null){//第一次判斷是為了提升效率,先判斷若不為null,鎖也沒必要搶,搶鎖開銷是很大的 synchronized (Singleton.class){ if(singleton==null){ singleton=new Singleton(); } } } return singleton; } }