大家好,我叫噬魂
2.1單例模式介紹
單例模式的應(yīng)用場景是:在一個(gè)應(yīng)用中,應(yīng)當(dāng)只有一個(gè)ImageLoader實(shí)例,這個(gè)實(shí)例ImageLoader中又有線程池,緩存系統(tǒng),網(wǎng)絡(luò)請求等,這些都很消耗資源,所以應(yīng)當(dāng)采用單例模式稍算。
2.2單例模式的定義
確保某個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例匾竿。
2.3單例模式UML類圖
角色介紹:
Client----高層客戶端
Singleton----單例類
實(shí)現(xiàn)單例模式有以下幾個(gè)關(guān)鍵點(diǎn):
1.構(gòu)造函數(shù)不對(duì)外開放,一般為private;
2.通過一個(gè)靜態(tài)方法或者枚舉返回單例類對(duì)象;
3.確保單例類只有一個(gè),尤其是在多線程的環(huán)境下;
4.確保單例類對(duì)象在反序列化時(shí)不會(huì)重新構(gòu)建對(duì)象(這個(gè)可能是很多人沒有注意到的)。
在獲取單例對(duì)象的時(shí)候,我們要確保線程安全,在多線程環(huán)境也只有一個(gè)對(duì)象,這在單例模式實(shí)現(xiàn)中比較困難英融。
2.4單例模式的簡單實(shí)現(xiàn)
示例實(shí)現(xiàn)代碼 coding
package com.dp.example.singleton;
//普通員工
public class Staff{
public void work(){
//干活
}
}
//副總裁
public class VP extends Staff{
@override
public void work(){
//管理下面的經(jīng)理
}
}
//CEO,惡漢單例模式
public class CEO extends Staff{
private static final CEO mCeo = new CEO();
//構(gòu)造函數(shù)私有
private CEO(){
}
//公有的靜態(tài)方法,對(duì)外暴露獲取單例對(duì)象的接口
public static CEO getCeo(){
return mCeo;
}
@override
public void work(){
//管理vp
}
}
//公司類
public class Company{
private List<Staff> allStaffs = new ArrayList<Staff>;
public void addStaff(Staff per){
allStaff.add(per);
}
public void showAllStaffs(){
for (Staff per: allStaffs ) {
System.out.println("Obj: "+ per.toString());
}
}
}
public class Test{
public static void man(String[] args){
Company cp = new Company();
//CEO對(duì)象只能用getCeo函數(shù)獲取
Staff ceo1 = CEO.getCeo();
Staff ceo2 = CEO.getCeo();
cp.addStaff(ceo1);
cp.addStaff(ceo2);
//通過new創(chuàng)建vp對(duì)象
Staff vp1 = new VP();
Staff vp2 = new VP();
//通過new創(chuàng)建staff對(duì)象
Staff staff1 = new Staff();
Staff staff2 = new Staff();
Staff staff3 = new Staff();
cp.addStaff(vp1);
cp.addStaff(vp2);
cp.addStaff(staff1);
cp.addStaff(staff2);
cp.addStaff(staff3);
cp.showAllStaffs();
}
}
2.5單例模式的其他實(shí)現(xiàn)方式
懶漢模式
public class singleton{
private static singleton instance;
private singleton (){};
public static synchronized singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
我們在getInstance()方法中添加了synchronized關(guān)鍵字克握,也就是一個(gè)同步方法霜医,這是為了保證在多線程中對(duì)象唯一性的手段事镣,不過這里有一個(gè)問題,就是當(dāng)instance已經(jīng)被初始化了之后竭讳,以后每次調(diào)用geitInstance方法都會(huì)進(jìn)行同步操作创葡,這樣會(huì)消耗不必要的資源浙踢,這就是懶漢式存在的最大問題绢慢。
最后總結(jié)一下:懶漢式的優(yōu)點(diǎn)是單例只有在使用時(shí)才會(huì)實(shí)例化,在一定程度上節(jié)約了資源洛波,缺點(diǎn)是第一次加載時(shí)需要及時(shí)進(jìn)行實(shí)例化胰舆,反應(yīng)稍慢,最大的問題是當(dāng)我們用geitIntance時(shí)蹬挤,每次都要同步缚窿,這樣就造成了不必要的開銷,懶漢式這種模式我們一般不推薦使用焰扳,我們還是建議使用下面幾種方式倦零。
Double Check Lock(DCL)
DCL方式實(shí)現(xiàn)單例模式的優(yōu)點(diǎn)是既能夠在需要的時(shí)候才初始化單例,又能夠保證線程安全吨悍,且單例對(duì)象初始化之后調(diào)用getInstance不進(jìn)行同步鎖扫茅。
public class Singleton{
private static Singleton sInstance = null;
private Singleton(){};
public void doSometing(){
System.out.println("do sth.");
}
public static Singleton getInstance(){
if(sInstance == null){
synchronized (Singleton.class){
if(sInstance == null){
sIntance = new Singleton();
}
}
}
return sIntance;
}
}
下面是比較好的實(shí)現(xiàn)方式
2.6 靜態(tài)內(nèi)部類單例模式
public class Singleton{
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
/**
*靜態(tài)內(nèi)部類
*/
private static class SingletonHolder{
private static final Singleton sInstance = new Singleton();
}
}
這種方式是我們推薦的方式。