java23种设计模式+单例_Java23种设计模式之单例模式
一、單例模式簡介
單例模式是Java設(shè)計(jì)模式中常見的一種模式。主要分為懶漢式單例、餓漢式單例、登記式單例;
單例模式的特點(diǎn): ?1、單例類只能有一個(gè)實(shí)例; ?2、單例類必須自己創(chuàng)建自己的唯一的實(shí)例; 3、單例類必須給所有其他對象提供這一實(shí)例;
二、餓漢式單例
public classSingleTonModel {privateSingleTonModel(){}private static final SingleTonModel singt=newSingleTonModel();public staticSingleTonModel getInstance(){returnsingt;
}
}
餓漢式在類創(chuàng)建的同時(shí)就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對象供系統(tǒng)使用,以后不再改變,所以天生是線程安全的。
三、懶漢式單例
簡單的例子:
public classSingleTonModel {privateSingleTonModel(){}private static SingleTonModel singt=null;public staticSingleTonModel getInstance(){if(singt==null){
singt=newSingleTonModel();
}returnsingt;
}
}
Singleton通過將構(gòu)造方法限定為private避免了類在外部被實(shí)例化,在同一個(gè)虛擬機(jī)范圍內(nèi),Singleton的唯一實(shí)例只能通過getInstance()方法訪問。
(事實(shí)上,通過Java反射機(jī)制是能夠?qū)嵗瘶?gòu)造方法為private的類的,那基本上會使所有的Java單例實(shí)現(xiàn)失效。此問題在此處不做討論,姑且掩耳盜鈴地認(rèn)為反射機(jī)制不存在。)
但是以上懶漢式單例的實(shí)現(xiàn)沒有考慮線程安全問題,它是線程不安全的,并發(fā)環(huán)境下很可能出現(xiàn)多個(gè)Singleton實(shí)例,要實(shí)現(xiàn)線程安全,有以下三種方式,都是對getInstance這個(gè)方法改造,保證了懶漢式單例的線程安全:(課外知識可以了解線程安全)
改造一:在靜態(tài)方法上添加關(guān)鍵詞:synchronized,進(jìn)行同步
public classSingleTonModel {privateSingleTonModel(){}private static SingleTonModel singt=null;public staticsynchronizedSingleTonModel getInstance(){if(singt==null){
singt=newSingleTonModel();
}returnsingt;
}
}
雖然通過同步保障了線程安全,但是每次都要同步,會影響性能,畢竟99%的情況下是不需要同步的。
改造二:在判斷不存在實(shí)例時(shí)才進(jìn)行同步
public classSingleTonModel {privateSingleTonModel(){}private static SingleTonModel singt=null;public staticSingleTonModel getInstance(){if(singt==null){
synchronized(SingleTonModel.class){if(singt==null){
singt=newSingleTonModel();
}
}
}returnsingt;
}
}
在getInstance中做了兩次null檢查,確保了只有第一次調(diào)用單例的時(shí)候才會做同步,這樣也是線程安全的,同時(shí)避免了每次都同步的性能損耗。
改造三:添加內(nèi)部靜態(tài)類
public classSingleTonModel {privateSingleTonModel(){}private static classlanSingleton{private static final SingleTonModel singt=newSingleTonModel();
}public staticfinal SingleTonModel getInstance(){returnlanSingleton.singt;
}
}
利用了classloader的機(jī)制來保證初始化instance時(shí)只有一個(gè)線程,所以也是線程安全的,同時(shí)沒有性能損耗,所以一般我傾向于使用這一種。
四、登記式單例(很少用)
/類似Spring里面的方法,將類名注冊,下次從里面直接獲取。public classSingleton3 {private static Map map = new HashMap();static{
Singleton3 single= newSingleton3();
map.put(single.getClass().getName(), single);
}//保護(hù)的默認(rèn)構(gòu)造子
protectedSingleton3(){}//靜態(tài)工廠方法,返還此類惟一的實(shí)例
public staticSingleton3 getInstance(String name) {if(name == null) {
name= Singleton3.class.getName();
System.out.println("name == null"+"--->name="+name);
}if(map.get(name) == null) {try{
map.put(name, (Singleton3) Class.forName(name).newInstance());
}catch(InstantiationException e) {
e.printStackTrace();
}catch(IllegalAccessException e) {
e.printStackTrace();
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}return map.get(name);
}//一個(gè)示意性的商業(yè)方法
publicString about() {return "Hello, I am RegSingleton.";
}public static voidmain(String[] args) {
Singleton3 single3= Singleton3.getInstance(null);
System.out.println(single3.about());
}
}
登記式單例實(shí)際上維護(hù)了一組單例類的實(shí)例,將這些實(shí)例存放在一個(gè)Map(登記薄)中,對于已經(jīng)登記過的實(shí)例,則從Map直接返回,對于沒有登記的,則先登記,然后返回。
課外小知識:
1、什么是線程安全
如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。
或者說:一個(gè)類或者程序所提供的接口對于線程來說是原子操作,或者多個(gè)線程之間的切換不會導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性,也就是說我們不用考慮同步的問題,那就是線程安全的。
總結(jié)
以上是生活随笔為你收集整理的java23种设计模式+单例_Java23种设计模式之单例模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java怎么添加地图_javaweb怎样
- 下一篇: java调用sql返回list_Hibe