看完這篇單例模式,終於敢和面試官對線了

2021-10-08 23:37:16 字數 3966 閱讀 4390

三、[推]列舉模式

四、[推]holder模式

五、總結

不想看過程的可以直接看結果

執行緒安全

懶載入反射破壞

餓漢模式

類載入就建立物件確保執行緒安全

立即載入

能避免懶漢模式

synchronized

synchronized對方法加鎖

懶載入不能避免

雙重檢測鎖

volatile(jdk>1.5)+判定+對類加鎖

懶載入不能避免

列舉模式

靜態**塊建立物件確保執行緒安全

立即載入

能避免holder模式(作者最愛)

載入內部類就建立物件確保執行緒安全

懶載入能避免

單例模式相信大家都很熟悉了,是一種很常用的設計模式,單例模式確保乙個類只有乙個例項,並提供乙個訪問它的全域性訪問點。作者曾經在一次面試中要求寫出單例模式,想了想單例模式還是簡單的,隨手就寫了如下**。

/**

* @author meng

* @date 2020/8/8

*/public

class

singleton

public

static singleton getinstance()

return instance;

}}

最後,不出意外的沒有通過面試。原因如下

這段**並沒***執行緒是安全的,是有可能導致獲取的物件不唯一。

這段**是可以通過反射破壞單例模式,拿到多個相同的物件。

在多執行緒的情況下,乙個執行緒已經進入到if裡面的**塊但是還沒有建立物件,突然切換到另外乙個執行緒,就有可能匯出建立的物件不一致。

執行緒a執行緒b

判斷物件不為空

判斷物件不為空

建立物件

返回物件

建立物件

返回物件

至於通過反射破壞單例模式,我們則是通過setaccessible(true)來強行訪問私有構造器,**如下

public

static

void

main

(string[

] args)

throws nosuchmethodexception, illegalacces***ception, invocationtargetexception, instantiationexception

經過總結,乙個單例模式的寫法,我們需要關注以下幾點。

/**

- @author meng

- @date 2020/8/10

*/public

class

singleton

}public

static

synchronized singleton getinstance()

}

餓漢模式的特點很明顯,它在類初始化的時候會建立物件,而該過程執行在類初始化(),而()是執行緒安全的,因此不擔心執行緒安全問題,但是缺點也容易明顯,就算沒有使用也會建立物件,容易浪費記憶體。同時構造器進行了判斷,如果想通過反射也會丟擲異常。

懶漢模式,顧名思義,就是很懶,用到才建立物件,屬於懶載入。作者一開始的例子就屬於懶漢模式,因此我們需要為其確保執行緒安全。但是懶漢模式難以防止反射破壞,詳情下面會分析

/**

- @author meng

- @date 2020/8/10

*/public

class

singleton

}public

static

synchronized singleton getinstance()

return instance;

}}

簡單粗暴,直接通過synchronized加鎖達到了執行緒安全,也像餓漢模式一樣在建構函式進行了判斷防止反射破壞。但是真的能防止反射嗎?它防止的只是先正常獲取物件,再反射,但是其實可以通過先反射,再正常的獲取物件,拿到兩個物件。**如下

public

static

void

main

(string[

] args)

throws nosuchmethodexception, illegalacces***ception, invocationtargetexception, instantiationexception

/**

- @author meng

- @date 2020/8/11

*/public

class

singleton

}public singleton getinstance()

}}return instance;

}}

該方法不是對整個方法加鎖,而是先進行判斷,再對類進行加鎖,同時使用volatile避免指令的重排序(需要jdk1.5以後),volatile關鍵字的作用這裡就不細談了。至於防止反射破壞,與上面的一樣,是不能避免的。

/**

3. @author meng

4. @create 2020/8/112

*/public

enum singleton

}

我們先看看列舉的本質

列舉只能擁有私有的構造器

列舉類實際上是乙個繼承enum的乙個final類

列舉類不允許被反序列化,enum重寫了方法

靜態**塊中對final變數的值進行初始化

enum類最終是乙個final class

列舉是執行緒安全的,所以列舉類裡的列舉會在靜態**塊建立物件,而該過程執行在類初始化(),而()是執行緒安全的

接下來就是作者最喜歡的holder模式,雖然列舉模式已經十分的完美,但是物件導向還是更多人喜歡class而不是enum.holder模式說白了就是通過靜態內部類來實現,先看**

/**

* @author meng

* @date 2020/8/11

*/public

class

singleton

}private

static

class

holder

public

static singleton getinstance()

}

在呼叫getinstance方法的時候,holder類才會被載入(這裡可以去看下類載入的時機),到了初始化階段會對靜態變數instance賦值,屬於()過程,而該過程是保證執行緒安全的靜態內部類在用到時候才會載入,因此該模式屬於延遲載入,與餓漢模式類似,私有構造方法進行判定避免了反射破壞。

執行緒安全

懶載入反射破壞

餓漢模式

類載入就建立物件確保執行緒安全

立即載入

能避免懶漢模式

synchronized

synchronized對方法加鎖

懶載入不能避免

雙重檢測鎖

volatile(jdk>1.5)+判定+對類加鎖

懶載入不能避免

列舉模式

靜態**塊建立物件確保執行緒安全

立即載入

能避免holder模式(作者最愛)

載入內部類就建立物件確保執行緒安全

懶載入能避免

看完這篇TCP,和面試官扯皮就沒問題了

無論什麼技術崗位,計算機網路幾乎是每場面試的必問內容,在面試 現的次數非常非常多,所以我面試之前也有所準備。看到csdn上介紹http的部落格比較多,tcp的比較少,於是今天結合面試問題先詳細講一講tcp。這部分之所以放在最前面,因為太重要!太重要!太重要了!源埠 目標埠 計算機上的程序要和其他程序...

面試官系統之設計模式(單例模式)

單例模式 顧名思義就是只能有乙個,不能在出現第二個。就如同地球上沒有兩片完全一模一樣的樹葉一樣。程式猿的角度理解 乙個類有且只能有乙個例項,不能出現第二個,並且整個專案系統中都能訪問該例項。面試官 為啥不能出現第二個?程式猿 這個面試官是笨蛋,出現第二個那就不叫單例模式了,那至少得叫雙例模式,是吧?...

吊錘面試官的單例模式大全

餓漢一 餓漢式優點 寫法簡單 執行緒安全的 缺點 還沒被呼叫就物件就被載入了,不夠節約 public class singleton public static singleton getinstance 測試方法用於證明餓漢單例模式下fianl修飾單例物件的作用 注意必須是餓漢式,懶漢式不考慮使用...