设计模式-享元模式
栗子
使用工廠方法,表現(xiàn)層通過工廠方法創(chuàng)建對(duì)象,再傳遞給業(yè)務(wù)層,持久層,最后保存到數(shù)據(jù)庫(kù)中。
報(bào)考信息
報(bào)考信息工廠,批量生產(chǎn)報(bào)考信息對(duì)象
public class SiginfoFactory{// 報(bào)名信息的對(duì)象工廠public static Signinfo getSigninfo(){return new Signinfo();} }最后書寫場(chǎng)景
public class Client{public static void main(String[] args){// 從工廠中獲得對(duì)象Signinfo signinfo = SigninfoFactory.getSigninfo();// 進(jìn)行其他業(yè)務(wù)處理} }垃圾回收機(jī)制
jvm有垃圾回收機(jī)制,即自動(dòng)內(nèi)存管理。其中堆是所有線程都共享的,而棧是每個(gè)線程都各自擁有的。
程序有程序計(jì)數(shù)器,當(dāng)線程超過cpu數(shù)量,或者cpu內(nèi)核數(shù)量的時(shí)候,線程根據(jù)時(shí)間片輪詢搶奪cpu時(shí)間資源,即每個(gè)線程都需要一個(gè)獨(dú)立的程序計(jì)數(shù)器記錄正在執(zhí)行的字節(jié)碼的指令地址。
虛擬機(jī)棧,虛擬機(jī)棧是java方法執(zhí)行的內(nèi)存模型,為線程私有,每個(gè)方法在執(zhí)行的時(shí)候,會(huì)創(chuàng)建一個(gè)棧幀,這個(gè)棧幀保存著局部變量表,操作數(shù)棧,動(dòng)態(tài)鏈接,方法出口,每個(gè)方法的調(diào)用,都代表著一個(gè)棧幀從入棧到出棧的過程。方法調(diào)用會(huì)入棧,方法返回會(huì)出棧
關(guān)于java堆,垃圾收集器的主要管理區(qū)域,即GC堆,java垃圾回收算法有引用計(jì)數(shù)法,通過判斷對(duì)象的引用數(shù)量決定對(duì)象是否可以被回收,當(dāng)引用為0的對(duì)象,可以被當(dāng)做垃圾回收,當(dāng)對(duì)象之間相互引用的時(shí)候,由于兩者引用計(jì)數(shù)都不為0,所以不能使用gc進(jìn)行清除。
可達(dá)性分析算法,程序把引用關(guān)系看做一張圖,從節(jié)點(diǎn)往下搜索,當(dāng)對(duì)象沒有任何引用鏈的時(shí)候,會(huì)證明不可達(dá),此時(shí)進(jìn)行回收
垃圾收集算法,對(duì)象先判斷是否可以進(jìn)行回收,先標(biāo)記再清除,從跟集合掃描,對(duì)存活對(duì)象標(biāo)記,標(biāo)記完成以后,對(duì)未標(biāo)記的進(jìn)行回收。復(fù)制算法。將可用內(nèi)存分大小相等兩塊,這一塊用完,將存活的復(fù)制到另外一塊上,再把已經(jīng)使用的內(nèi)存空間一次清除掉。即,將堆空間分為兩塊,一塊為新生代,一塊為老年代,在進(jìn)行回收的時(shí)候,會(huì)把存活的對(duì)象,復(fù)制到新生代中,將老年代清空。
內(nèi)存泄露
使用HashMap,Vector等集合類的靜態(tài)使用容易出現(xiàn)內(nèi)存泄露,因?yàn)檫@些靜態(tài)變量的生命周期和應(yīng)用程序一致。
即各種資源的連接,網(wǎng)絡(luò)連接,IO連接沒有被close關(guān)閉,
更改
當(dāng)并發(fā)數(shù)增多的時(shí)候,每個(gè)線程會(huì)創(chuàng)建對(duì)象,并發(fā)數(shù)越多,線程數(shù)越多,此時(shí)會(huì)造成內(nèi)存的瘋狂占用,造成內(nèi)存泄露。
解決:對(duì)象池。使用一個(gè)共享池來解決問題。
代碼如下
下面書寫帶對(duì)象池的工廠類
public class SigninfoFactory{// 池容器private static HashMap<String, Signinfo> pool = new hashMap<String, Signinfo>();// 對(duì)象工廠@Deprecated// 對(duì)原先代碼進(jìn)行修改的時(shí)候,需要加上Deprecated,表明這個(gè)方法已經(jīng)廢棄。不在建議使用,不建議刪除,因?yàn)槿绻衅渌^續(xù)使用這個(gè)方法的時(shí)候,將會(huì)導(dǎo)致出現(xiàn)不可預(yù)知的問題。用于向下兼容public static Signinfo(){return new Signinfo();}// 獲得對(duì)象public static Signinfo getSigninfo(String key){Signinfo result = null;// 當(dāng)key值存在的時(shí)候,從對(duì)象池中獲得該對(duì)象。當(dāng)key值不存在的時(shí)候,創(chuàng)建對(duì)象,并放入對(duì)象池中。if(!pool.containsKey(key)){result = new Signinfo4Pool(key);pool.put(key, result);}else{result = pool.get(key);}return result;}}最后書寫場(chǎng)景類
public class Client{public static void main(String[] args){// 初始化對(duì)象池for(int i = 0 ; i < 4; i++){String subject = "科目" + i;// 初始化地址for(int j = 0; j < 30; j++){String key = subject + "地點(diǎn)" + j;SigninfoFactory.getSigninfo(key);}}// 從池中獲取對(duì)象然后進(jìn)行處理。Signinfo singinfo = SignInfoFactory.getSignInfo("科目1地點(diǎn)1");} }總結(jié)
即,將共性的內(nèi)容,提取出來,然后在新建一個(gè)子類,然后在子類中預(yù)留出外部訪問的。上方的栗子為key。然后在工廠模式中,String為key,value的值為key對(duì)應(yīng)的對(duì)象池中創(chuàng)建的對(duì)象。
ps 在上方的栗子中id作為附屬的,即,對(duì)象的動(dòng)態(tài)信息。池 + 工廠
通過新建一個(gè)對(duì)象池,該池內(nèi)的對(duì)象有HashMap來進(jìn)行保存,然后通過工廠,輸入key值,獲取到對(duì)象。
核心在于創(chuàng)建出業(yè)務(wù)需要的對(duì)象,然后在運(yùn)行的時(shí)候,直接使用該對(duì)象。因?yàn)槎咽撬芯€程所共享的。
線程安全
由于java中堆是所有線程所共享的,所以當(dāng)共享池中的對(duì)象數(shù)不夠的時(shí)候,會(huì)出現(xiàn)線程安全的問題,即,多個(gè)線程,共同訪問一個(gè)對(duì)象,同時(shí)修改造成數(shù)據(jù)的錯(cuò)誤。
即,在使用享元模式的時(shí)候,對(duì)象要盡可能的多,直到業(yè)務(wù)需求全部滿足。還要注意線程安全的問題,當(dāng)一個(gè)線程
外部狀態(tài)/內(nèi)部狀態(tài)
關(guān)于外部狀態(tài)和內(nèi)部狀態(tài),其中內(nèi)部狀態(tài)不可更改,外部狀態(tài)可更改,但是多線程的時(shí)候會(huì)出現(xiàn)很嚴(yán)重的問題,即線程不安全,當(dāng)多個(gè)線程共同訪問,操作外部狀態(tài)的時(shí)候,會(huì)出現(xiàn)線程不安全。至今不知道怎么解決。
繼續(xù)擴(kuò)展
此時(shí),新建一個(gè)類,用于保存key值,替代原先的String方式。
再寫static類型的里面保存的HashMap,用于保存當(dāng)前池中的對(duì)象。
需要使用的時(shí)候,直接新將外部類,將內(nèi)容set進(jìn)入。
工廠內(nèi)需要調(diào)用狀態(tài)類的方法,生成String和HashMap中的key進(jìn)行對(duì)比。若已經(jīng)生成,直接返回該對(duì)象,否則不返回該對(duì)象
總結(jié)
享元模式 = 工廠模式 + 池
總結(jié)
- 上一篇: Trustdata:映客直播站稳行业第一
- 下一篇: View 绘制流程分析