真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java技能的優(yōu)化方法有哪些

這篇文章主要講解了“Java技能的優(yōu)化方法有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Java技能的優(yōu)化方法有哪些”吧!

白銀區(qū)ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

1         通用篇

“通用篇”討論的問題適合于大多數(shù)Java應(yīng)用。

1.1      不用new關(guān)鍵詞創(chuàng)建類的實(shí)例

用new關(guān)鍵詞創(chuàng)建類的實(shí)例時,構(gòu)造函數(shù)鏈中的所有構(gòu)造函數(shù)都會被自動調(diào)用。但如果一個對象實(shí)現(xiàn)了Cloneable接口,我們可以調(diào)用它的clone()方法。clone()方法不會調(diào)用任何類構(gòu)造函數(shù)。

在使用設(shè)計(jì)模式(Design Pattern)的場合,如果用Factory模式創(chuàng)建對象,則改用clone()方法創(chuàng)建新的對象實(shí)例非常簡單。例如,下面是Factory模式的一個典型實(shí)現(xiàn):

public static Credit getNewCredit() { return new Credit(); }

改進(jìn)后的代碼使用clone()方法,如下所示:

private static Credit BaseCredit = new Credit(); public static Credit getNewCredit() { return (Credit) BaseCredit.clone(); }

上面的思路對于數(shù)組處理同樣很有用。

1.2      使用非阻塞I/O

版本較低的JDK不支持非阻塞I/O API。為避免I/O阻塞,一些應(yīng)用采用了創(chuàng)建大量線程的辦法(在較好的情況下,會使用一個緩沖池)。這種技術(shù)可以在許多必須支持并發(fā)I/O流的應(yīng)用中見到,如Web服務(wù)器、報(bào)價和拍賣應(yīng)用等。然而,創(chuàng)建Java線程需要相當(dāng)可觀的開銷。

JDK 1.4引入了非阻塞的I/O庫(java.nio)。如果應(yīng)用要求使用版本較早的JDK,在這里有一個支持非阻塞I/O的軟件包。

請參見Sun中國網(wǎng)站的《調(diào)整Java的I/O性能》。

1.3      慎用異常

異常對性能不利。拋出異常首先要創(chuàng)建一個新的對象。Throwable接口的構(gòu)造函數(shù)調(diào)用名為fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆棧,收集調(diào)用跟蹤信息。只要有異常被拋出,VM就必須調(diào)整調(diào)用堆棧,因?yàn)樵谔幚磉^程中創(chuàng)建了一個新的對象。

異常只能用于錯誤處理,不應(yīng)該用來控制程序流程。

1.4    不要重復(fù)初始化變量

默認(rèn)情況下,調(diào)用類的構(gòu)造函數(shù)時, Java會把變量初始化成確定的值:所有的對象被設(shè)置成null,整數(shù)變量(byte、short、int、long)設(shè)置成0,float和 double變量設(shè)置成0.0,邏輯值設(shè)置成false。當(dāng)一個類從另一個類派生時,這一點(diǎn)尤其應(yīng)該注意,因?yàn)橛胣ew關(guān)鍵詞創(chuàng)建一個對象時,構(gòu)造函數(shù)鏈中的所有構(gòu)造函數(shù)都會被自動調(diào)用。

1.5      盡量指定類的final修飾符

帶有final修飾符的類是不可派生的。在Java核心API中,有許多應(yīng)用final的例子,例如java.lang.String。為String類指定final防止了人們覆蓋length()方法。

另外,如果指定一個類為final,則該類所有的方法都是final。Java編譯器會尋找機(jī)會內(nèi)聯(lián)(inline)所有的final方法(這和具體的編譯器實(shí)現(xiàn)有關(guān))。此舉能夠使性能平均提高50%。

1.6      盡量使用局部變量

調(diào)用方法時傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時變量都保存在棧(Stack)中,速度較快。其他變量,如靜態(tài)變量、實(shí)例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。另外,依賴于具體的編譯器/JVM,局部變量還可能得到進(jìn)一步優(yōu)化。請參見《盡可能使用堆棧變量》。

1.7      乘法和除法

考慮下面的代碼:

for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }

用移位操作替代乘法操作可以極大地提高性能。下面是修改后的代碼:

for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }

修改后的代碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當(dāng)于乘以2。相應(yīng)地,右移1位操作相當(dāng)于除以2。值得一提的是,雖然移位操作速度快,但可能使代碼比較難于理解,所以***加上一些注釋。

2         J2EE篇

前面介紹的改善性能技巧適合于大多數(shù)Java應(yīng)用,接下來要討論的問題適合于使用JSP、EJB或JDBC的應(yīng)用。

2.1      使用緩沖標(biāo)記

一些應(yīng)用服務(wù)器加入了面向JSP的緩沖標(biāo)記功能。例如,BEA的WebLogic Server從6.0版本開始支持這個功能,Open Symphony工程也同樣支持這個功能。JSP緩沖標(biāo)記既能夠緩沖頁面片斷,也能夠緩沖整個頁面。當(dāng)JSP頁面執(zhí)行時,如果目標(biāo)片斷已經(jīng)在緩沖之中,則生成該片斷的代碼就不用再執(zhí)行。頁面級緩沖捕獲對指定URL的請求,并緩沖整個結(jié)果頁面。對于購物籃、目錄以及門戶網(wǎng)站的主頁來說,這個功能極其有用。對于這類應(yīng)用,頁面級緩沖能夠保存頁面執(zhí)行的結(jié)果,供后繼請求使用。

對于代碼邏輯復(fù)雜的頁面,利用緩沖標(biāo)記提高性能的效果比較明顯;反之,效果可能略遜一籌。

請參見《用緩沖技術(shù)提高JSP應(yīng)用的性能和穩(wěn)定性》。

2.2      始終通過會話Bean訪問實(shí)體Bean

直接訪問實(shí)體Bean不利于性能。當(dāng)客戶程序遠(yuǎn)程訪問實(shí)體Bean時,每一個get方法都是一個遠(yuǎn)程調(diào)用。訪問實(shí)體Bean的會話Bean是本地的,能夠把所有數(shù)據(jù)組織成一個結(jié)構(gòu),然后返回它的值。

用會話Bean封裝對實(shí)體Bean的訪問能夠改進(jìn)事務(wù)管理,因?yàn)闀払ean只有在到達(dá)事務(wù)邊界時才會提交。每一個對get方法的直接調(diào)用產(chǎn)生一個事務(wù),容器將在每一個實(shí)體Bean的事務(wù)之后執(zhí)行一個“裝入-讀取”操作。

一些時候,使用實(shí)體Bean會導(dǎo)致程序性能不佳。如果實(shí)體Bean的唯一用途就是提取和更新數(shù)據(jù),改成在會話Bean之內(nèi)利用JDBC訪問數(shù)據(jù)庫可以得到更好的性能。

2.3      選擇合適的引用機(jī)制

在典型的JSP應(yīng)用系統(tǒng)中,頁頭、頁腳部分往往被抽取出來,然后根據(jù)需要引入頁頭、頁腳。當(dāng)前,在JSP頁面中引入外部資源的方法主要有兩種:include指令,以及include動作。

include指令:例如:

<%@ include file="copyright.html" %>

該指令在編譯時引入指定的資源。在編譯之前,帶有include指令的頁面和指定的資源被合并成一個文件。被引用的外部資源在編譯時就確定,比運(yùn)行時才確定資源更高效。

include動作:例如。該動作引入指定頁面執(zhí)行后生成的結(jié)果。由于它在運(yùn)行時完成,因此對輸出結(jié)果的控制更加靈活。但時,只有當(dāng)被引用的內(nèi)容頻繁地改變時,或者在對主頁面的請求沒有出現(xiàn)之前,被引用的頁面無法確定時,使用include動作才合算。

2.4      在部署描述器中設(shè)置只讀屬性

實(shí)體Bean的部署描述器允許把所有g(shù)et方法設(shè)置成“只讀”。當(dāng)某個事務(wù)單元的工作只包含執(zhí)行讀取操作的方法時,設(shè)置只讀屬性有利于提高性能,因?yàn)槿萜鞑槐卦賵?zhí)行存儲操作。

2.5      緩沖對EJB Home的訪問

EJB Home接口通過JNDI名稱查找獲得。這個操作需要相當(dāng)可觀的開銷。JNDI查找***放入Servlet的init()方法里面。如果應(yīng)用中多處頻繁地出現(xiàn)EJB訪問,***創(chuàng)建一個EJBHomeCache類。EJBHomeCache類一般應(yīng)該作為singleton實(shí)現(xiàn)。

2.6      為EJB實(shí)現(xiàn)本地接口

本地接口是EJB 2.0規(guī)范新增的內(nèi)容,它使得Bean能夠避免遠(yuǎn)程調(diào)用的開銷。請考慮下面的代碼。

PayBeanHome home = (PayBeanHome) javax.rmi.PortableRemoteObject.narrow (ctx.lookup ("PayBeanHome"), PayBeanHome.class); PayBean bean = (PayBean) javax.rmi.PortableRemoteObject.narrow (home.create(), PayBean.class);

***個語句表示我們要尋找Bean的Home接口。這個查找通過JNDI進(jìn)行,它是一個RMI調(diào)用。然后,我們定位遠(yuǎn)程對象,返回代理引用,這也是一個 RMI調(diào)用。第二個語句示范了如何創(chuàng)建一個實(shí)例,涉及了創(chuàng)建IIOP請求并在網(wǎng)絡(luò)上傳輸請求的stub程序,它也是一個RMI調(diào)用。要實(shí)現(xiàn)本地接口,我們必須作如下修改:方法不能再拋出java.rmi.RemoteException異常,包括從RemoteException派生的異常,比如 TransactionRequiredException、TransactionRolledBackException和 NoSuchObjectException。EJB提供了等價的本地異常,如TransactionRequiredLocalException、 TransactionRolledBackLocalException和NoSuchObjectLocalException。

所有數(shù)據(jù)和返回值都通過引用的方式傳遞,而不是傳遞值。

本地接口必須在EJB部署的機(jī)器上使用。簡而言之,客戶程序和提供服務(wù)的組件必須在同一個JVM上運(yùn)行。

如果Bean實(shí)現(xiàn)了本地接口,則其引用不可串行化。

請參見《用本地引用提高EJB訪問效率》。

2.7      生成主鍵

在EJB之內(nèi)生成主鍵有許多途徑,下面分析了幾種常見的辦法以及它們的特點(diǎn)。

利用數(shù)據(jù)庫內(nèi)建的標(biāo)識機(jī)制(SQL Server的IDENTITY或Oracle的SEQUENCE)。這種方法的缺點(diǎn)是EJB可移植性差。

由實(shí)體Bean自己計(jì)算主鍵值(比如做增量操作)。它的缺點(diǎn)是要求事務(wù)可串行化,而且速度也較慢。

利用NTP之類的時鐘服務(wù)。這要求有面向特定平臺的本地代碼,從而把Bean固定到了特定的OS之上。另外,它還導(dǎo)致了這樣一種可能,即在多CPU的服務(wù)器上,同一個毫秒之內(nèi)生成了兩個主鍵。

借鑒Microsoft的思路,在Bean中創(chuàng)建一個GUID。然而,如果不求助于JNI,Java不能確定網(wǎng)卡的MAC地址;如果使用JNI,則程序就要依賴于特定的OS。

還有其他幾種辦法,但這些辦法同樣都有各自的局限。似乎只有一個答案比較理想:結(jié)合運(yùn)用RMI和JNDI。先通過RMI注冊把RMI遠(yuǎn)程對象綁定到JNDI樹??蛻舫绦蛲ㄟ^JNDI進(jìn)行查找。下面是一個例子:

public class keyGenerator extends UnicastRemoteObject implements Remote { private static long KeyValue = System.currentTimeMillis(); public static synchronized long getKey() throws RemoteException { return KeyValue++; }

2.8      及時清除不再需要的會話

為了清除不再活動的會話,許多應(yīng)用服務(wù)器都有默認(rèn)的會話超時時間,一般為30分鐘。當(dāng)應(yīng)用服務(wù)器需要保存更多會話時,如果內(nèi)存容量不足,操作系統(tǒng)會把部分內(nèi)存數(shù)據(jù)轉(zhuǎn)移到磁盤,應(yīng)用服務(wù)器也可能根據(jù)“最近最頻繁使用”(Most Recently Used)算法把部分不活躍的會話轉(zhuǎn)儲到磁盤,甚至可能拋出“內(nèi)存不足”異常。在大規(guī)模系統(tǒng)中,串行化會話的代價是很昂貴的。當(dāng)會話不再需要時,應(yīng)當(dāng)及時調(diào)用HttpSession.invalidate()方法清除會話。HttpSession.invalidate()方法通??梢栽趹?yīng)用的退出頁面調(diào)用。

2.9      在JSP頁面中關(guān)閉無用的會話

對于那些無需跟蹤會話狀態(tài)的頁面,關(guān)閉自動創(chuàng)建的會話可以節(jié)省一些資源。使用如下page指令:

<%@ page session="false"%>

2.10   Servlet與內(nèi)存使用

許多開發(fā)者隨意地把大量信息保存到用戶會話之中。一些時候,保存在會話中的對象沒有及時地被垃圾回收機(jī)制回收。從性能上看,典型的癥狀是用戶感到系統(tǒng)周期性地變慢,卻又不能把原因歸于任何一個具體的組件。如果監(jiān)視JVM的堆空間,它的表現(xiàn)是內(nèi)存占用不正常地大起大落。

解決這類內(nèi)存問題主要有二種辦法。***種辦法是,在所有作用范圍為會話的Bean中實(shí)現(xiàn)HttpSessionBindingListener接口。這樣,只要實(shí)現(xiàn)valueUnbound()方法,就可以顯式地另外一種辦法就是盡快地把會話作廢。大多數(shù)應(yīng)用服務(wù)器都有設(shè)置會話作廢間隔時間的選項(xiàng)。另外,也可以用編程的方式調(diào)用會話的 setMaxInactiveInterval()方法,該方法用來設(shè)定在作廢會話之前,Servlet容器允許的客戶請求的***間隔時間,以秒計(jì)。

2.11   HTTP Keep-Alive

Keep-Alive功能使客戶端到服務(wù)器端的連接持續(xù)有效,當(dāng)出現(xiàn)對服務(wù)器的后繼請求時,Keep-Alive功能避免了建立或者重新建立連接。市場上的大部分Web服務(wù)器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。對于提供靜態(tài)內(nèi)容的網(wǎng)站來說,這個功能通常很有用。但是,對于負(fù)擔(dān)較重的網(wǎng)站來說,這里存在另外一個問題:雖然為客戶保留打開的連接有一定的好處,但它同樣影響了性能,因?yàn)樵谔幚頃和F陂g,本來可以釋放的資源仍舊被占用。當(dāng)Web服務(wù)器和應(yīng)用服務(wù)器在同一臺機(jī)器上運(yùn)行時,Keep- Alive功能對資源利用的影響尤其突出。

2.12   JDBC與Unicode

想必你已經(jīng)了解一些使用JDBC時提高性能的措施,比如利用連接池、正確地選擇存儲過程和直接執(zhí)行的SQL、從結(jié)果集刪除多余的列、預(yù)先編譯SQL語句,等等。

除了這些顯而易見的選擇之外,另一個提高性能的好選擇可能就是把所有的字符數(shù)據(jù)都保存為Unicode(代碼頁13488)。Java以Unicode形式處理所有數(shù)據(jù),因此,數(shù)據(jù)庫驅(qū)動程序不必再執(zhí)行轉(zhuǎn)換過程。但應(yīng)該記?。喝绻捎眠@種方式,數(shù)據(jù)庫會變得更大,因?yàn)槊總€Unicode字符需要2個字節(jié)存儲空間。另外,如果有其他非Unicode的程序訪問數(shù)據(jù)庫,性能問題仍舊會出現(xiàn),因?yàn)檫@時數(shù)據(jù)庫驅(qū)動程序仍舊必須執(zhí)行轉(zhuǎn)換過程。

2.13   JDBC與I/O

如果應(yīng)用程序需要訪問一個規(guī)模很大的數(shù)據(jù)集,則應(yīng)當(dāng)考慮使用塊提取方式。默認(rèn)情況下,JDBC每次提取32行數(shù)據(jù)。舉例來說,假設(shè)我們要遍歷一個5000 行的記錄集,JDBC必須調(diào)用數(shù)據(jù)庫157次才能提取到全部數(shù)據(jù)。如果把塊大小改成512,則調(diào)用數(shù)據(jù)庫的次數(shù)將減少到10次。

在一些情形下這種技術(shù)無效。例如,如果使用可滾動的記錄集,或者在查詢中指定了FOR UPDATE,則塊操作方式不再有效。

2.14   內(nèi)存數(shù)據(jù)庫

許多應(yīng)用需要以用戶為單位在會話對象中保存相當(dāng)數(shù)量的數(shù)據(jù),典型的應(yīng)用如購物籃和目錄等。由于這類數(shù)據(jù)可以按照行/列的形式組織,因此,許多應(yīng)用創(chuàng)建了龐大的Vector或HashMap。在會話中保存這類數(shù)據(jù)極大地限制了應(yīng)用的可伸縮性,因?yàn)榉?wù)器擁有的內(nèi)存至少必須達(dá)到每個會話占用的內(nèi)存數(shù)量乘以并發(fā)用戶***數(shù)量,它不僅使服務(wù)器價格昂貴,而且垃圾收集的時間間隔也可能延長到難以忍受的程度。一些人把購物籃/目錄功能轉(zhuǎn)移到數(shù)據(jù)庫層,在一定程度上提高了可伸縮性。然而,把這部分功能放到數(shù)據(jù)庫層也存在問題,且問題的根源與大多數(shù)關(guān)系數(shù)據(jù)庫系統(tǒng)的體系結(jié)構(gòu)有關(guān)。對于關(guān)系數(shù)據(jù)庫來說,運(yùn)行時的重要原則之一是確保所有的寫入操作穩(wěn)定、可靠,因而,所有的性能問題都與物理上把數(shù)據(jù)寫入磁盤的能力有關(guān)。關(guān)系數(shù)據(jù)庫力圖減少I/O操作,特別是對于讀操作,但實(shí)現(xiàn)該目標(biāo)的主要途徑只是執(zhí)行一套實(shí)現(xiàn)緩沖機(jī)制的復(fù)雜算法,而這正是數(shù)據(jù)庫層***號性能瓶頸通常總是 CPU的主要原因。

一種替代傳統(tǒng)關(guān)系數(shù)據(jù)庫的方案是,使用在內(nèi)存中運(yùn)行的數(shù)據(jù)庫(In-memory Database),例如TimesTen。內(nèi)存數(shù)據(jù)庫的出發(fā)點(diǎn)是允許數(shù)據(jù)臨時地寫入,但這些數(shù)據(jù)不必***地保存到磁盤上,所有的操作都在內(nèi)存中進(jìn)行。這樣,內(nèi)存數(shù)據(jù)庫不需要復(fù)雜的算法來減少I/O操作,而且可以采用比較簡單的加鎖機(jī)制,因而速度很快。

3    GUI篇

這一部分介紹的內(nèi)容適合于圖形用戶界面的應(yīng)用(Applet和普通應(yīng)用),要用到AWT或Swing。

3.1      用JAR壓縮類文件

Java檔案文件(JAR文件)是根據(jù)JavaBean標(biāo)準(zhǔn)壓縮的文件,是發(fā)布JavaBean組件的主要方式和推薦方式。JAR檔案有助于減少文件體積,縮短下載時間。例如,它有助于Applet提高啟動速度。一個JAR文件可以包含一個或者多個相關(guān)的Bean以及支持文件,比如圖形、聲音、HTML 和其他資源。

要在HTML/JSP文件中指定JAR文件,只需在Applet標(biāo)記中加入ARCHIVE = "name.jar"聲明。

請參見《使用檔案文件提高 applet 的加載速度》。

3.2      提示Applet裝入進(jìn)程

你是否看到過使用Applet的網(wǎng)站,注意到在應(yīng)該運(yùn)行Applet的地方出現(xiàn)了一個占位符?當(dāng)Applet的下載時間較長時,會發(fā)生什么事情?***的可能就是用戶掉頭離去。在這種情況下,顯示一個Applet正在下載的信息無疑有助于鼓勵用戶繼續(xù)等待。下面我們來看看一種具體的實(shí)現(xiàn)方法。首先創(chuàng)建一個很小的Applet,該Applet負(fù)責(zé)在后臺下載正式的Applet:

import java.applet.Applet; import java.applet.AppletStub; import java.awt.Label; import java.awt.Graphics; import java.awt.GridLayout; public class PreLoader extends Applet implements Runnable, AppletStub { String largeAppletName; Label label; public void init() { // 要求裝載的正式Applet largeAppletName = getParameter("applet"); // “請稍等”提示信息 label = new Label("請稍等..." + largeAppletName); add(label); } public void run(){ try { // 獲得待裝載Applet的類 Class largeAppletClass = Class.forName(largeAppletName); // 創(chuàng)建待裝載Applet的實(shí)例 Applet largeApplet = (Applet)largeAppletClass.newInstance(); // 設(shè)置該Applet的Stub程序 largeApplet.setStub(this); // 取消“請稍等”信息 remove(label); // 設(shè)置布局 setLayout(new GridLayout(1, 0)); add(largeApplet); // 顯示正式的Applet largeApplet.init(); largeApplet.start(); } catch (Exception ex) { // 顯示錯誤信息 label.setText("不能裝入指定的Applet"); } // 刷新屏幕 validate(); } public void appletResize(int width, int height) { // 把a(bǔ)ppletResize調(diào)用從stub程序傳遞到Applet resize(width, height); } }

編譯后的代碼小于2K,下載速度很快。代碼中有幾個地方值得注意。首先,PreLoader實(shí)現(xiàn)了AppletStub接口。一般地,Applet從調(diào)用者判斷自己的codebase。在本例中,我們必須調(diào)用setStub()告訴Applet到哪里提取這個信息。另一個值得注意的地方是, AppletStub接口包含許多和Applet類一樣的方法,但appletResize()方法除外。這里我們把對appletResize()方法的調(diào)用傳遞給了resize()方法。

3.3      在畫出圖形之前預(yù)先裝入它

ImageObserver接口可用來接收圖形裝入的提示信息。ImageObserver接口只有一個方法imageUpdate(),能夠用一次repaint()操作在屏幕上畫出圖形。下面提供了一個例子。

public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) { if ((flags & ALLBITS) !=0 { repaint(); } else if (flags & (ERROR |ABORT )) != 0) { error = true; // 文件沒有找到,考慮顯示一個占位符 repaint(); } return (flags & (ALLBITS | ERROR| ABORT)) == 0; }

當(dāng)圖形信息可用時,imageUpdate()方法被調(diào)用。如果需要進(jìn)一步更新,該方法返回true;如果所需信息已經(jīng)得到,該方法返回false。

3.4      覆蓋update方法

update()方法的默認(rèn)動作是清除屏幕,然后調(diào)用paint()方法。如果使用默認(rèn)的update()方法,頻繁使用圖形的應(yīng)用可能出現(xiàn)顯示閃爍現(xiàn)象。要避免在paint()調(diào)用之前的屏幕清除操作,只需按照如下方式覆蓋update()方法:

public void update(Graphics g) { paint(g); }

更理想的方案是:覆蓋update(),只重畫屏幕上發(fā)生變化的區(qū)域,如下所示:

public void update(Graphics g) { g.clipRect(x, y, w, h); paint(g); }

3.5      延遲重畫操作

對于圖形用戶界面的應(yīng)用來說,性能低下的主要原因往往可以歸結(jié)為重畫屏幕的效率低下。當(dāng)用戶改變窗口大小或者滾動一個窗口時,這一點(diǎn)通常可以很明顯地觀察到。改變窗口大小或者滾動屏幕之類的操作導(dǎo)致重畫屏幕事件大量地、快速地生成,甚至超過了相關(guān)代碼的執(zhí)行速度。對付這個問題***的辦法是忽略所有“遲到” 的事件。

建議在這里引入一個數(shù)毫秒的時差,即如果我們立即接收到了另一個重畫事件,可以停止處理當(dāng)前事件轉(zhuǎn)而處理***一個收到的重畫事件;否則,我們繼續(xù)進(jìn)行當(dāng)前的重畫過程。

如果事件要啟動一項(xiàng)耗時的工作,分離出一個工作線程是一種較好的處理方式;否則,一些部件可能被“凍結(jié)”,因?yàn)槊看沃荒芴幚硪粋€事件。下面提供了一個事件處理的簡單例子,但經(jīng)過擴(kuò)展后它可以用來控制工作線程。

public static void runOnce(String id, final long milliseconds) { synchronized(e_queue) { // e_queue: 所有事件的集合 if (!e_queue.containsKey(id)) { e_queue.put(token, new LastOne()); } } final LastOne lastOne = (LastOne) e_queue.get(token); final long time = System.currentTimeMillis(); // 獲得當(dāng)前時間 lastOne.time = time; (new Thread() {public void run() { if (milliseconds > 0) { try {Thread.sleep(milliseconds);} // 暫停線程 catch (Exception ex) {} } synchronized(lastOne.running) { // 等待上一事件結(jié)束 if (lastOne.time != time) // 只處理***一個事件 return; } }}).start(); } private static Hashtable e_queue = new Hashtable(); private static class LastOne { public long time=0; public Object running = new Object(); }

3.6      使用雙緩沖區(qū)

在屏幕之外的緩沖區(qū)繪圖,完成后立即把整個圖形顯示出來。由于有兩個緩沖區(qū),所以程序可以來回切換。這樣,我們可以用一個低優(yōu)先級的線程負(fù)責(zé)畫圖,使得程序能夠利用空閑的CPU時間執(zhí)行其他任務(wù)。下面的偽代碼片斷示范了這種技術(shù)。

Graphics myGraphics; Image myOffscreenImage = createImage(size().width, size().height); Graphics offscreenGraphics = myOffscreenImage.getGraphics(); offscreenGraphics.drawImage(img, 50, 50, this); myGraphics.drawImage(myOffscreenImage, 0, 0, this);

3.7      使用BufferedImage

Java JDK 1.2使用了一個軟顯示設(shè)備,使得文本在不同的平臺上看起來相似。為實(shí)現(xiàn)這個功能,Java必須直接處理構(gòu)成文字的像素。由于這種技術(shù)要在內(nèi)存中大量地進(jìn)行位復(fù)制操作,早期的JDK在使用這種技術(shù)時性能不佳。為解決這個問題而提出的Java標(biāo)準(zhǔn)實(shí)現(xiàn)了一種新的圖形類型,即BufferedImage。

BufferedImage子類描述的圖形帶有一個可訪問的圖形數(shù)據(jù)緩沖區(qū)。一個BufferedImage包含一個ColorModel和一組光柵圖形數(shù)據(jù)。這個類一般使用RGB(紅、綠、藍(lán))顏色模型,但也可以處理灰度級圖形。它的構(gòu)造函數(shù)很簡單,如下所示:

public BufferedImage (int width, int height, int imageType)

ImageType允許我們指定要緩沖的是什么類型的圖形,比如5-位RGB、8-位RGB、灰度級等。

3.8      使用VolatileImage

許多硬件平臺和它們的操作系統(tǒng)都提供基本的硬件加速支持。例如,硬件加速一般提供矩形填充功能,和利用CPU完成同一任務(wù)相比,硬件加速的效率更高。由于硬件加速分離了一部分工作,允許多個工作流并發(fā)進(jìn)行,從而緩解了對CPU和系統(tǒng)總線的壓力,使得應(yīng)用能夠運(yùn)行得更快。利用VolatileImage可以創(chuàng)建硬件加速的圖形以及管理圖形的內(nèi)容。由于它直接利用低層平臺的能力,性能的改善程度主要取決于系統(tǒng)使用的圖形適配器。VolatileImage的內(nèi)容隨時可能丟失,也即它是“不穩(wěn)定的(volatile)”。因此,在使用圖形之前,***檢查一下它的內(nèi)容是否丟失。VolatileImage有兩個能夠檢查內(nèi)容是否丟失的方法:

public abstract int validate(GraphicsConfiguration gc); public abstract Boolean contentsLost();

每次從VolatileImage對象復(fù)制內(nèi)容或者寫入VolatileImage時,應(yīng)該調(diào)用validate()方法。contentsLost()方法告訴我們,自從***一次validate()調(diào)用之后,圖形的內(nèi)容是否丟失。

雖然VolatileImage是一個抽象類,但不要從它這里派生子類。VolatileImage應(yīng)該通過 Component.createVolatileImage()或者 GraphicsConfiguration.createCompatibleVolatileImage()方法創(chuàng)建。

3.9      使用Window Blitting

進(jìn)行滾動操作時,所有可見的內(nèi)容一般都要重畫,從而導(dǎo)致大量不必要的重畫工作。許多操作系統(tǒng)的圖形子系統(tǒng),包括WIN32 GDI、MacOS和X/Windows,都支持Window Blitting技術(shù)。Window Blitting技術(shù)直接在屏幕緩沖區(qū)中把圖形移到新的位置,只重畫新出現(xiàn)的區(qū)域。要在Swing應(yīng)用中使用Window Blitting技術(shù),設(shè)置方法如下:

setScrollMode(int mode);

在大多數(shù)應(yīng)用中,使用這種技術(shù)能夠提高滾動速度。只有在一種情形下,Window Blitting會導(dǎo)致性能降低,即應(yīng)用在后臺進(jìn)行滾動操作。如果是用戶在滾動一個應(yīng)用,那么它總是在前臺,無需擔(dān)心任何負(fù)面影響。

感謝各位的閱讀,以上就是“Java技能的優(yōu)化方法有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Java技能的優(yōu)化方法有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!


文章名稱:Java技能的優(yōu)化方法有哪些
本文地址:http://weahome.cn/article/gpjsdo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部