色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

JAVA中用動(dòng)態(tài)代理類實(shí)現(xiàn)記憶功能(二)

瀏覽:5日期:2024-06-23 08:54:26
內(nèi)容: 通過(guò)動(dòng)態(tài)代理類來(lái)創(chuàng)建一個(gè)通用的緩存包裝器 上面第二種方法僅有的缺點(diǎn)就是緩存包裝器不能重用,每次我們希望添加一個(gè)緩存給某個(gè)類,我們就要寫(xiě)一個(gè)特殊的緩存包裝器給目標(biāo)接口.這是一個(gè)很慢,容易出錯(cuò)的過(guò)程. Jdk1.3開(kāi)始支持動(dòng)態(tài)代理類: 特別的類能夠在運(yùn)行期決定實(shí)現(xiàn)哪個(gè)接口-通常的模式都是,在運(yùn)行期即決定實(shí)現(xiàn)哪個(gè)接口.通過(guò)這個(gè),我們有可能實(shí)現(xiàn)一個(gè)通用的緩存包裝器,我們稱它為Memoizer,在運(yùn)行期決定實(shí)現(xiàn)哪個(gè)接口.這樣, CachingBinaryDigitsCalculator就是不再需要的.它是這樣被調(diào)用的:BinaryDigitsCalculator calculator = new CachingBinaryDigitsCalculator( new PiBinaryDigitsCalculator() );可以通過(guò)Memoizer來(lái)重寫(xiě)如下:BinaryDigitsCalculator calculator = (BinaryDigitsCalculator) Memoizer.memoize( new PiBinaryDigitsCalculator() );Memoizer的代碼如下:import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Arrays;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;public class Memoizer implements InvocationHandler { public static Object memoize(Object object) { return Proxy.newProxyInstance( object.getClass().getClassLoader(), object.getClass().getInterfaces(), new Memoizer(object) ); } private Object object; private Map caches = new HashMap(); private Memoizer(Object object) { this.object = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getReturnType().equals(Void.TYPE)) { // Don't cache void methods return invoke(method, args); } else { Map cache = getCache(method); List key = Arrays.asList(args); Object value = cache.get(key); if (value == null && !cache.containsKey(key)) { value = invoke(method, args); cache.put(key, value); } return value; } } private Object invoke(Method method, Object[] args) throws Throwable { try { return method.invoke(object, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } private synchronized Map getCache(Method m) { Map cache = (Map) caches.get(m); if (cache == null) { cache = Collections.synchronizedMap( new HashMap() ); caches.put(m, cache); } return cache; }} 當(dāng)調(diào)用靜態(tài)方法memoize的時(shí)候,將會(huì)創(chuàng)建一個(gè)新的代理實(shí)例-也就是一個(gè)java.lang.reflect.proxy的實(shí)例.實(shí)現(xiàn)了一個(gè)接口集.這個(gè)接口集由object.getClass().getInterfaces()來(lái)決定.每個(gè)代理實(shí)例包含一個(gè)java.lang.reflect.InvocationHandler實(shí)例來(lái)處理這個(gè)代理實(shí)例調(diào)用的相關(guān)方法.在我們的例子里,Memoizer就是一個(gè)InvocationHandler實(shí)例. 當(dāng)一個(gè)方法在代理實(shí)例里被調(diào)用,比如, calculateBinaryDigit,那么, Memoizer實(shí)例里的invoke方法就會(huì)被調(diào)用,相關(guān)信息會(huì)傳給invoke方法,以決定proxy實(shí)例調(diào)用了哪個(gè)方法,包含參數(shù)信息.在我們的例子里,傳入Memoizer的java.lang.Method參數(shù)是calculateBinaryDigit,而參數(shù)信息則是pi需要精確的位數(shù)-整數(shù)n.在這個(gè)基礎(chǔ)上,Memoizer能夠進(jìn)一步進(jìn)行緩存操作的. 在例子里(caches是一個(gè)Hashmap,cache是一個(gè)map)里用到的Key,主要是傳入的方法信息:Method對(duì)象和參數(shù)對(duì)象. 為了實(shí)現(xiàn)的簡(jiǎn)單與通用性,Memoizer有一個(gè)關(guān)于cache的HashMap caches,每個(gè)method是一個(gè)key,對(duì)應(yīng)的value為一個(gè)cache.然后把參數(shù)信息轉(zhuǎn)化成一個(gè)List對(duì)象,作為cache的Key.使用List是很方便的,同時(shí)也可以保證equals()方法,所以能夠保證當(dāng)且僅當(dāng)參數(shù)信息完全相同的時(shí)候這個(gè)List才相等. 一旦一個(gè)cache的Key被創(chuàng)建,那么,計(jì)算之前都會(huì)先查找這個(gè)cache,如果找到,則返回cache里的值.否則,如果帶有這些參數(shù)的這個(gè)方法沒(méi)有被調(diào)用過(guò),那么,則會(huì)通過(guò)invoke來(lái)調(diào)用這個(gè)method.在我們的例子里, 實(shí)例PiBinaryDigitsCalculator 里的calculateBinaryDigit方法將會(huì)通過(guò)invoke被調(diào)用.而且計(jì)算結(jié)果將會(huì)被存在cache里.何時(shí)使用Memoizer 作為一條通用的規(guī)則,Memoizer能夠在任何需要傳統(tǒng)的cache的時(shí)候使用-比如上面提到的例子. 特別地,接口里每個(gè)需要使用記憶功能的method需要滿足下面幾條條件:1. 這個(gè)method的返回值最好不要每次調(diào)用都會(huì)改變2. 這個(gè)method不要有副效應(yīng)3. 這個(gè)method的參數(shù)是確定的,非mutable的. 顯然,如果每次調(diào)用這個(gè)method返回值都不同,那么cache就毫無(wú)用處了.同樣也是很重要的一點(diǎn)是,因?yàn)橛懈毙?yīng)的method不會(huì)被重復(fù),所以這個(gè)method不能有副效應(yīng)(method自動(dòng)更新某些狀態(tài)).當(dāng)然,void方法除外. 同樣,memorize一個(gè)帶有未定(mutable)參數(shù)的method是很危險(xiǎn)的,因?yàn)?要把這些參數(shù)儲(chǔ)存到hashmap里會(huì)是很危險(xiǎn)的一件事.根據(jù)Map的定義,當(dāng)這個(gè)Map里的key發(fā)生改變,Map是不知道的.所以,當(dāng)你執(zhí)行了一次這個(gè)method之后,相關(guān)信息添加進(jìn)了Map,然后參數(shù)發(fā)生變異(mutate),第二次調(diào)用的時(shí)候,就會(huì)得到錯(cuò)誤的結(jié)果.性能 使用cache的主要目的就是為了提升你的程序的速度.然而,reflection確是眾所周知的低效(在jdk1.4里有所改進(jìn),通過(guò)reflection調(diào)用方法是普通調(diào)用速度的1/2,這個(gè)比jdk1.3要快40倍).Memoizer主要依靠reflection來(lái)調(diào)用方法,所以,它看上去并不是一個(gè)好的途徑.但是,如果使用cache能給程序速度帶來(lái)的提升遠(yuǎn)高于reflection對(duì)速度的影響,那么,使用Memoizer是值得考慮的. 在我們對(duì)PiBinaryDigitsCalculator的測(cè)試中,測(cè)試環(huán)境為jdk1.4,當(dāng)n小于10的時(shí)候,使不使用cache速度是相當(dāng)?shù)?但是,當(dāng)n增大的時(shí)候,使用cache的優(yōu)勢(shì)就開(kāi)始顯示出來(lái).所以,經(jīng)常使用PiBinaryDigitsCalculator的用戶,可以考慮使用cache. 不幸的是,唯一測(cè)試你的程序是否需要cache的途徑是比較你的程序在兩種情況下的運(yùn)行效率.盡管如此,因?yàn)闉橐粋€(gè)程序構(gòu)造一個(gè)cache包裝器是很容易的一件事,移除它也是很容易的,下面的建議可以作為一個(gè)參考的步驟:1. 選擇需要記憶操作的類2. 運(yùn)行它3. 如果效率是滿意的,go to 64. 添加memoizer,使用cache5. 如果效率沒(méi)有顯著提升,移初memoizer6. 如果需要,重試. 理論上,你需要分析為一個(gè)類添加記憶功能對(duì)整個(gè)系統(tǒng)的影響.只有你自己清楚是否值得添加.有些方法,即使是計(jì)算量很大的,但是在這個(gè)系統(tǒng)里很少被調(diào)用,所以,沒(méi)必要為它添加記憶功能.為了保證這個(gè),我開(kāi)發(fā)了一個(gè)更有特點(diǎn)的Memoizer,實(shí)現(xiàn)了一個(gè)叫做CacheStatistics的接口,你能從它得到cache的數(shù)量以及無(wú)效的cache.你可以使用它作為判斷的一個(gè)尺度.擴(kuò)展Memoizer 修改Memoizer類來(lái)支持不同的cache策略是很簡(jiǎn)單的.一個(gè)比較普通的類型就是Least-Recently-Used(LRU)cahce,擁有固定數(shù)量的入口.這個(gè)cache確保入口不大于它的最大數(shù)目,如果超過(guò),就摒棄最舊的緩存數(shù)據(jù).也就是,能夠從cache里得到的是新的數(shù)據(jù).一個(gè)類可以使用LRU cache來(lái)防止一個(gè)程序長(zhǎng)期保持一個(gè)狀態(tài).你可以僅僅傳遞一個(gè)參數(shù)給CacheFactory里的memoize方法來(lái)選擇你需要的cache類型.下面的例子,LRU cache最多有1000個(gè)入口:BinaryDigitsCalculator calculator = (BinaryDigitsCalculator) Memoizer.memoize( new PiBinaryDigitsCalculator(), new LruCacheFactory(1000) ); 即使是這么簡(jiǎn)單,Memoizer也應(yīng)該是java程序員一個(gè)有用的工具.參考資源:• Joshua Bloch, Effective Java Programming Language Guide. Addison Wesley Professional (2001). Contains useful advice about optimization. • Patrick Chan, The Java Developers Almanac 1.4. Addison Wesley Professional (2002). Full of Java recipes, including how to write a LRU cache. • Paul Graham, On Lisp. Prentice Hall (1993). How to write a memoizing function in Common Lisp. • Alex Martelli and David Ascher (Eds.), Python Cookbook. O'Reilly (July 2002). Recipe 17.7, Memoizing (Caching) the Return Values of Functions shows you how to memoize in Python. • Documentation for LinkedHashMap in Java SDK 1.4 • Documentation for Proxy in Java SDK 1.4 • The Memoizer Framework 關(guān)于翻譯作者chris,熱衷于java游戲引擎技術(shù),jvm技術(shù),活躍于jxta社區(qū).可以點(diǎn)擊:http://www.matrix.org.cn/user_view.asp?username=chris查看他的個(gè)人信息 Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 成人a视频 | 国产三级精品最新在线 | 久草热视频在线观看 | 久久99亚洲精品久久久久99 | 国内精品久久久久久网站 | 欧美国产精品一区二区免费 | 欧美日韩免费播放一区二区 | 亚洲黄色免费观看 | 一区二区三区免费在线视频 | 久久久久999 | 亚洲天堂在线视频观看 | 美女视频黄的免费视频网页 | 在线观看免费为成年视频 | 91久久香蕉国产线看 | 欧美专区一区 | 欧美.成人.综合在线 | 一级啪啪片 | 亚洲男人的天堂成人 | 欧美一区a| 久草天堂| 中文字幕 日韩在线 | 欧美在线日韩在线 | 女人张开腿让男人桶免费网站 | 操欧美女 | 失禁h啪肉尿出来高h男男 | 免费看a| 国产精品国产 | caoporen个人免费公开视频 | 日本亚洲成高清一区二区三区 | 精品久久久久久中文字幕网 | 国产精品大全 | 精品国产一区二区三区在线观看 | 国产精品亚欧美一区二区三区 | 亚洲 午夜在线一区 | 国产成人mv 在线播放 | 91高端极品外围在线观看 | 一级风流片a级国产 | 91av久久| 久久久久久一品道精品免费看 | 中文久草| 亚洲国产精品成人综合久久久 |