餓漢式:
public class Singleton{
public static final Singleton INSTANCE = new Singleton();
// 注意將默認(rèn)的無(wú)參構(gòu)造方法訪問(wèn)權(quán)限符置為private,防止外部調(diào)用該構(gòu)造方法會(huì)new出更多對(duì)象實(shí)例
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
單例實(shí)現(xiàn)缺點(diǎn):
- 如果構(gòu)造方法存在過(guò)多的處理事甜,會(huì)導(dǎo)致加載這個(gè)類(lèi)很慢婆排,可能會(huì)引起性能問(wèn)題
- 在未調(diào)用getInstance方法時(shí)串结,JVM也會(huì)在加載Singleton類(lèi)時(shí)候去實(shí)例化靜態(tài)字段的INSTANCE啸驯,造成內(nèi)存資源的浪費(fèi)
懶漢式:
public class Singleton{
public static Singleton INSTANCE;
// 注意將默認(rèn)的無(wú)參構(gòu)造方法訪問(wèn)權(quán)限符置為private,防止外部調(diào)用該構(gòu)造方法會(huì)new出更多對(duì)象實(shí)例
private Singleton(){}
/**
多線程情況下喊括,會(huì)出現(xiàn)生成多個(gè)實(shí)例對(duì)象問(wèn)題,導(dǎo)致單例失效
**/
public static Singleton getInstance_1(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
/**
加上synchronized實(shí)現(xiàn)線程同步窃页,可解決多線程情況下單例失效問(wèn)題跺株,但是考慮到getInstance()方法是一個(gè)被頻繁調(diào)用的方法,這時(shí)候會(huì)出現(xiàn)性能下降問(wèn)題脖卖,一般不推薦使用這種實(shí)現(xiàn)單例的方式
*/
public static synchronized Singleton getInstance_2(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
雙重檢查加鎖模式(DCL model)
ublic class Singleton{
public static volatile Singleton INSTANCE;
// 注意將默認(rèn)的無(wú)參構(gòu)造方法訪問(wèn)權(quán)限符置為private,防止外部調(diào)用該構(gòu)造方法會(huì)new出更多對(duì)象實(shí)例
private Singleton(){}
public static Singleton getInstance(){
if(INSTANCE == null){
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
volatile是一個(gè)輕量級(jí)的synchronized乒省,它在多處理器開(kāi)發(fā)中保證了共享變量的可見(jiàn)性
利用static機(jī)制:
在Java中,類(lèi)的靜態(tài)初始化會(huì)在類(lèi)被加載時(shí)出發(fā)(此過(guò)程在JVM內(nèi)部已加鎖畦木,保證線程同步袖扛,因此多線程情況下單例不會(huì)失效)
ublic class Singleton{
// 注意將默認(rèn)的無(wú)參構(gòu)造方法訪問(wèn)權(quán)限符置為private,防止外部調(diào)用該構(gòu)造方法會(huì)new出更多對(duì)象實(shí)例
private Singleton(){}
public static Singleton getInstance(){
return SingletonInstanceHolder.INSTANCE;
}
public static class SingletonInstanceHolder{
private static Singleton INSTANCE = new Singleton();
}
}
需要思考一下:?jiǎn)卫J秸娴哪鼙WC只生成一個(gè)實(shí)例對(duì)象嗎?
其實(shí)要打破實(shí)例對(duì)象的唯一性十籍,也是有方法來(lái)實(shí)現(xiàn)的:
- 使用反射蛆封,反射可以無(wú)視構(gòu)造器的私有屬性
- 如果單例類(lèi)實(shí)現(xiàn)了Cloneable接口,還是可以拷貝出許多個(gè)實(shí)例的
- Java的Serializable也可以創(chuàng)建出多個(gè)實(shí)例來(lái)的
- 使用多個(gè)類(lèi)加載器(ClassLoader)來(lái)加載單例類(lèi)勾栗,也可以創(chuàng)建出多個(gè)實(shí)例來(lái)的