public class Singleton2 {
private Singleton2() {}
private static Singleton2 instance;
public static Singleton2 getInstance() {
if(instance == null) {
synchronized(Singleton2.class) {
if (instance == null) {
instance = new Singleton2();
}
}
}
return instance;
}
}
優(yōu)點:不需要在每次調(diào)用時加鎖,效率比上一個高
缺點:雖然使用了synchronized,但本質(zhì)上是線程不安全的
3. 雙重檢查(Double Check)下的懶漢
public class Singleton3 {
private static volatile Singleton3 instance;
private Singleton3() {}
public static Singleton3 getInstance() {
if (instance == null) {
synchronized(Singleton3.class) {
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
優(yōu)點:使用了雙重檢查,避免了線程不安全,同時避免了不必要的鎖開銷
缺點:無
注意:使用volatile關(guān)鍵字的目的不是保證可見性(synchronized已經(jīng)保證了可見性),而是為了保證順序性。具體來說,instance = new Singleton3()不是原子操作,實際上被拆分為了三步:1) 分配內(nèi)存;2) 初始化對象;3) 將instance指向分配的對象內(nèi)存地址。 如果沒有volatile,可能會發(fā)生指令重排序,使得instance先指向內(nèi)存地址,而對象尚未初始化,其它線程直接使用instance引用進行對象操作時出錯。詳細原理可參見《雙重檢查鎖定與延遲初始化》
4. 利用靜態(tài)變量(餓漢)
public class Singleton4 {
private Singleton4() {}
private static Singleton4 instance = new Singleton4();
public static Singleton4 getInstance() {
return instance;
}
}
優(yōu)點:實現(xiàn)簡單,無線程同步問題
缺點:在類裝載時完成實例化。若該實例一直未被使用,則會造成資源浪費
5. 利用靜態(tài)代碼塊(餓漢)
public class Singleton5 {
private static Singleton5 instance;
private Singleton5() {}
static {
instance = new Singleton5();
}
public static Singleton5 getInstance() {
return instance;
}
}
優(yōu)點:實現(xiàn)簡單,無線程同步問題
缺點:在類裝載時完成實例化。若該實例一直未被使用,則會造成資源浪費
6. 實現(xiàn)按需創(chuàng)建實例(強烈推薦)(懶漢)
public class Singleton6 {
private Singleton6() {}
private static class Nested {
private static Singleton6 instance = new Singleton6();
}
public static Singleton6 getInstance() {
return Nested.instance;
}
}
優(yōu)點:無線程同步問題,實現(xiàn)了懶加載。因為只有調(diào)用getInstance()時才會裝載內(nèi)部類,才會創(chuàng)建實例。同時因為使用內(nèi)部類,先調(diào)用內(nèi)部類的線程會獲得類初始化鎖,從而保證內(nèi)部類的初始化(包括實例化它所引用的外部類對象)線程安全。即使內(nèi)部類創(chuàng)建外部類的實例Singleton6 instance = new Singleton6()發(fā)生指令重排也不會引起雙重檢查下的懶漢模式中提到的問題,因此無須使用volatile關(guān)鍵字。