回顧概念:
Java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,我在這裏主要介紹兩種:懶漢式單例和餓漢式單例。
單例模式有以下特點:
1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。
單例模式確保某個類只有一個實例,而且自行實例化並向整個系統提供這個實例。在計算機系統中,線程池、緩存、日誌對象、對話框、打印機、顯卡的驅動程序對象常被設計成單例。
一、懶漢模式
懶漢模式:類加載器在加載類的時候,不會創建實例,只有當需要創建對象的時候,纔會去創建類的實例。
1、最簡單的,但不是線程安全的懶漢模式。
public class Singleton {
//私有化構造方法,防止外部使用new來創建對象。
private Singleton () {}
private static Singleton single = null;
public static Singleton getInstance () {
if(single == null) {
single = new Singleton();
}
return single;
}
}
2、線程安全的懶漢模式,但是實際運行中效果很差,類似數據庫中的表鎖。
public class Singleton {
//私有化構造方法,防止外部使用new來創建對象。
private Singleton () {}
private static Singleton single = null;
public static synchronized Singleton getInstance () {
if(single == null) {
single = new Singleton();
}
return single;
}
}
3、雙重校驗鎖,類似數據庫中的行鎖
public class Singleton {
//私有化構造方法,防止外部使用new來創建對象。
private Singleton () {}
//volatile關鍵字用於線程可見
private static volatile Singleton single = null;
public static Singleton getInstance () {
if(single == null) {
//鎖住類對象
synchronized(Singleton.Class) {
if(single == null) {
single = new Singleton();
}
}
return single;
}
}
}
4、靜態內部類方法
public class Singleton {
//私有化構造方法,防止外部使用new來創建對象。
private Singleton () {}
private static class LazyHolder {
//被final修飾的實例變量是無法被修改的,這就保證的對象的唯一性
private static final Singleton single = new Singleton();
}
public static Singleton getInstance() {
return LazyHolder.single;
}
}
二、餓漢模式
餓漢模式:類加載器加載的過程中,就已經創建好實例,因爲是在類加載初始階段就已經加載好了實例,所以餓漢模式總是線程安全的。
5、最簡單的,
public class Singleton {
//私有化構造方法,防止外部使用new來創建對象。
private Singleton () {}
//被final修飾的實例變量是無法被修改的,這就保證的對象的唯一性
private static final Singleton single =new Singleton();
public static synchronized Singleton getInstance () {
return single;
}
}
6、與5同理,但是代碼實現方式不同
public class Singleton {
//私有化構造方法,防止外部使用new來創建對象。
private Singleton () {}
//被final修飾的實例變量是無法被修改的,這就保證的對象的唯一性
private static final Singleton single = null;
//被static修飾的靜態代碼塊會在類加載期間,類加載器直接運行。
static {
single = new Singleton();
}
public static synchronized Singleton getInstance () {
return single;
}
}
總結:建議在選擇單例模式的時候選擇用雙重校驗鎖或靜態內部類的方式,這兩種方式能夠實現併發效率最優,但是當你確定某個類一定會被創建實例時,餓漢也是不錯的選擇。
參考博客:
JAVA設計模式之單例模式