單例設(shè)計(jì)模式(Singleton Pattern)
是Java最簡單的設(shè)計(jì)模式味混,相信很多人都應(yīng)用過蔓挖,但是你的真的完全了解單例設(shè)計(jì)模式嗎?
1.餓漢式--最簡單的單例設(shè)計(jì)模式(比較常用)
public class DataManager {
private static final DataManager instance = new DataManager();
private DataManager (){}
public static DataManager getInstance(){
return instance;
}
}
優(yōu)點(diǎn):
1.寫法簡單
2.線程安全
缺點(diǎn):
- 1.不能傳遞參數(shù)拷获。
- 2.類加載的時(shí)候就初始化了對象未蝌,浪費(fèi)內(nèi)存左冬。
2.懶漢式
這個(gè)單例設(shè)計(jì)模式梅忌,相對來說稍微復(fù)雜一些(比較常用)
public class DataManager {
//懶漢式
private static DataManager instance;
private DataManager(){}
public static DataManager getInstance(){
if (null == instance){
instance = new DataManager();
}
return instance;
}
}
這個(gè)方式略顯復(fù)雜,如果是沒有多線程的情況下蹋笼,使用很方便效率也比較高圾笨,并且還可以傳遞參數(shù)。但是悲敷,線程不安全后德,多線程的時(shí)候可能產(chǎn)生多個(gè)對象的情況。那么如何解決這個(gè)問題,請看下面這個(gè)方式
3.懶漢式+線程安全
為了解決懶漢式非線程安全的問題落蝙,加個(gè)鎖來解決這個(gè)問題。
public class DataManager {
//懶漢式+線程安全
private static DataManager instance;
private DataManager(){}
public static synchronized DataManager getInstance(){
if (null == instance){
instance = new DataManager();
}
return instance;
}
}
相對于純餓漢式只是增加了一個(gè)synchronized 關(guān)鍵字,這樣在多線程的情況下能夠很好的工作病瞳,但是存在一個(gè)明顯的問題就是效率低亲善,%99的情況下是不需要同步的。那么能否既可以線程安全又效率比較高渣蜗,請看下面這個(gè)實(shí)現(xiàn)方式
4.雙重校驗(yàn)鎖實(shí)現(xiàn)方式
為了解決單純添加同步關(guān)鍵字帶來的問題,使用double check 這個(gè)實(shí)現(xiàn)方式
public class DataManager {
//雙重校驗(yàn)鎖
private volatile static DataManager instance;
private DataManager(){}
public static DataManager getInstance(){
if (null == instance){
synchronized(DataManager.class){
if (null !=null){
instance = new DataManager();
}
}
}
return instance;
}
}
這個(gè)實(shí)現(xiàn)方式闰围,比較復(fù)雜一些碧查,但是能很好的保證在多線程下良好的運(yùn)行肤视,并且效率也比較高腐螟。
注意volatile這個(gè)關(guān)鍵字的使用
- 保證了不同線程對這個(gè)變量操作的可見性摇予,即某個(gè)線程修改了這個(gè)變量在其他線程會立即可見
- 禁止指令重排
如果不添加這個(gè)關(guān)鍵字宁昭,在多cpu的情況下可能出現(xiàn)線程不同步的問題出現(xiàn)疆拘。
5.靜態(tài)內(nèi)部類的方式
public class DataManager {
private DataManager(){}
private static class DataManagerHelper{
private static final DataManager instance = new DataManager();
}
public static DataManager getInstance(){
return DataManagerHelper.instance;
}
}
這種方式寫法簡單漱挚,也是線程安全(是由類加載機(jī)制保證的)
6.枚舉的方式
public enum DataManager {
INSTANCE;
public void doSomething(){
System.out.println("do something");
}
}
這個(gè)方式實(shí)現(xiàn)是最簡單的租漂,效率也是最高的秃踩,推薦使用這個(gè)方式。
以上就是常見的單例的設(shè)計(jì)模式的實(shí)現(xiàn)方式蒜胖,根據(jù)項(xiàng)目需求選擇合適的方式進(jìn)行使用即可。
單例設(shè)計(jì)模式的擴(kuò)展,多例設(shè)計(jì)
public class DataManager {
//單例設(shè)計(jì)模式的擴(kuò)展
private static final int MAX = 3;
private static Map<Integer,DataManager> mDataManager=new HashMap<>();
private static int index=1;
private volatile static DataManager instance;
private DataManager(){}
public static DataManager getInstance(){
instance = mDataManager.get(index);
if (null == instance){
synchronized(DataManager.class){
if (null ==null){
instance = new DataManager();
mDataManager.put(index,instance);
}
}
}
index++;
if (index>MAX){
index=1;
}
return instance;
}
}
上面這個(gè)實(shí)現(xiàn)方式也就是多例模式蒂胞,通過參數(shù)MAX就可以控制創(chuàng)建實(shí)例的個(gè)數(shù)了岳瞭,一些數(shù)據(jù)庫連接池牡昆、網(wǎng)絡(luò)的連接池就是這個(gè)方式實(shí)現(xiàn)的。
針對單例設(shè)計(jì)模式就寫到這里了,本人水平有限如果存在不足之處,歡迎指正與交流。