新聞中心
在Android的android.os.Message類的文檔中有這么一句話:
創(chuàng)新互聯(lián)建站是一家專注于成都網(wǎng)站制作、成都做網(wǎng)站與策劃設(shè)計(jì),鄲城網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)建站做網(wǎng)站,專注于網(wǎng)站建設(shè)十余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:鄲城等地區(qū)。鄲城做網(wǎng)站價(jià)格咨詢:13518219792While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.
大意是說(shuō),雖然Message類的構(gòu)造方法是public的,你可以直接通過(guò)new來(lái)創(chuàng)建一個(gè)新的對(duì)象,但是最好還是通過(guò)Message.obtain()或者Handler.obtainMessage()來(lái)創(chuàng)建一個(gè)新的Message對(duì)象,因?yàn)檫@兩個(gè)方法會(huì)重用之前創(chuàng)建的但是已經(jīng)不再使用了的對(duì)象實(shí)例。
這句話不禁引起了我的興趣,因?yàn)橹拔覍戇^(guò)一篇博客《Pool, SimplePool與SynchronizedPool》,在這篇博客里面仔細(xì)分析了Android是如何實(shí)現(xiàn)一個(gè)對(duì)象池的。里面提到VelocityTracker就是用SynchronizedPool來(lái)實(shí)現(xiàn)對(duì)象重用的,代碼如下:
VelocityTracker tracker = VelocityTracker.obtain(); tracker.recycle();
Message類看起來(lái)也略有相似,不過(guò)經(jīng)過(guò)閱讀Message類的源代碼,發(fā)現(xiàn)我錯(cuò)了,Message類使用了另一種巧妙的方法來(lái)實(shí)現(xiàn)對(duì)象重用。
好了,不賣關(guān)子了,Message類使用了一個(gè)鏈表來(lái)實(shí)現(xiàn)對(duì)象池,而且是一個(gè)前端鏈表,即在前端插入和刪除的鏈表,避免了插入和刪除的時(shí)候遍歷整個(gè)鏈表。是不是有點(diǎn)出人意料?
首先看一下這段代碼,去除了Message中其他的攜帶消息信息的字段。已經(jīng)很明顯可以看出來(lái)是一個(gè)鏈表了吧。
public final class Message implements Parcelable { // 省略其他代碼 Message next; // (1) private static final Object sPoolSync = new Object(); // (2) private static Message sPool; // (3) private static int sPoolSize = 0; // (4) private static final int MAX_POOL_SIZE = 50; // 省略其他代碼 }
(1) 聲明了next指針
(2) 對(duì)象鎖,Message對(duì)象池是線程安全的,這樣就需要在向?qū)ο蟪厣暾?qǐng)和歸還對(duì)象時(shí)使用鎖
(3) 這里是關(guān)鍵,一個(gè)靜態(tài)的Message對(duì)象,這就是這個(gè)鏈表的頭指針了,因?yàn)槭穷愖兞浚虼耍麄€(gè)JVM中只有一個(gè)
(4) 當(dāng)前對(duì)象池的大小,后面還限制了這個(gè)Message對(duì)象池中的對(duì)象個(gè)數(shù)大為50
用圖形表示如下:
繼續(xù)閱讀代碼,又發(fā)現(xiàn)了一個(gè)讓人困惑的問(wèn)題,看這個(gè)方法:
public static Message obtain() { synchronized (sPoolSync) { // (1) if (sPool != null) { Message m = sPool; // (2) sPool = m.next; // (3) m.next = null; // (4) sPoolSize--; // (5) return m; } } return new Message(); }
這也很容易理解:
(1) 獲取鎖,這里毫無(wú)疑義
(2) 當(dāng)頭指針指向的對(duì)象不為null時(shí),將這個(gè)對(duì)象賦值給m
(3) 將頭指針指向m的next指針
(4) 將m的next指向null,到這里位置,我們從以sPool為頭指針的鏈表中取出了第一個(gè)元素
(5) 將鏈表size減1
看起來(lái)沒(méi)錯(cuò),疑問(wèn)是,當(dāng)?shù)谝淮潍@取對(duì)象的時(shí)候sPool肯定為null,那么這個(gè)if語(yǔ)句肯定不會(huì)執(zhí)行,會(huì)直接執(zhí)行最后一句return new Message(),直接創(chuàng)建一個(gè)對(duì)象?這樣不是毫無(wú)意義了么?
看到這里,似乎感覺(jué)發(fā)現(xiàn)了一個(gè)Android的bug,會(huì)有這么明顯的bug么?當(dāng)然不會(huì),靜下心來(lái)繼續(xù)讀代碼,讀到這里的時(shí)候豁然開朗了:
public void recycle() { clearForRecycle(); // (1) synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { // (2) next = sPool; // (3) sPool = this; // (4) sPoolSize++; } } }
(1) 重置Message中攜帶的消息
(2) 檢查當(dāng)前對(duì)象池的大小是不是已經(jīng)超過(guò)了大值,如果當(dāng)前隊(duì)列已經(jīng)滿了,就不管這個(gè)對(duì)象了,讓JVM的GC回收好了,這里保證了性能的同時(shí)兼顧了內(nèi)存消耗
(3) 將當(dāng)前對(duì)象next指針指向頭指針sPool指向的對(duì)象
(4) 將頭指針sPool指向當(dāng)前對(duì)象,然后將對(duì)象池大小加1
到這里就明白了:這篇博客開頭的那句話其實(shí)背后還有一些潛臺(tái)詞,那就是你必須顯式的調(diào)用一下recycle()將當(dāng)前的Message對(duì)象歸還到對(duì)象池,這個(gè)對(duì)象池才能發(fā)揮其效果,不調(diào)用recycle()方法,對(duì)象不會(huì)歸還,會(huì)被JVM GC回收。
也就是說(shuō)下面兩句話必須是成對(duì)出現(xiàn)的,不用obtain()而調(diào)用recycle()會(huì)導(dǎo)致不停的創(chuàng)建Message對(duì)象直到超過(guò)MAX_POOL_SIZE的限制而被對(duì)象池扔掉;通過(guò)obtain()申請(qǐng)對(duì)象而不用recycle()歸還會(huì)導(dǎo)致對(duì)象池被消耗干凈而不停申請(qǐng)新對(duì)象。
Message msg = Message.obtain(); msg.recycle();
所以文檔再完整還是不如看代碼。
對(duì)于通過(guò)SynchronizedPool來(lái)實(shí)現(xiàn)對(duì)象池和這種通過(guò)鏈表來(lái)實(shí)現(xiàn)對(duì)象池兩種方法,我看不出來(lái)各自有何優(yōu)缺點(diǎn),這兩種方法很相似,實(shí)現(xiàn)的功能也相似,唯一的不同在于,前者似乎更容易擴(kuò)展。也許你自己在其他項(xiàng)目中需要對(duì)象池的時(shí)候,可以借鑒一下這兩種方法。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
分享題目:Android中的Message類以及Java對(duì)象池的實(shí)現(xiàn)-創(chuàng)新互聯(lián)
本文來(lái)源:http://ef60e0e.cn/article/dhjcgj.html