1 對(duì)Collection、Map接口的類對(duì)象初始化時(shí)要先分配合理的空間大小,同時(shí)還要按照自已的實(shí)際需求選擇合適的對(duì)象。
例如:聲明Vector vect=new Vector()時(shí),系統(tǒng)調(diào)用:
public Vector() {
// 缺省構(gòu)造函數(shù)
this(10);
// 容量是
10;}
缺省分配10個(gè)對(duì)象大小容量。
2 優(yōu)化循環(huán)體
循環(huán)是比較重復(fù)運(yùn)行的地方,如果循環(huán)次數(shù)很大,循環(huán)體內(nèi)不好的代碼對(duì)效率的影響就會(huì)被放大而變的突出。
3 少用new初始化一個(gè)實(shí)例
盡量少用new來(lái)初始化一個(gè)類的實(shí)例,當(dāng)一個(gè)對(duì)象是用new進(jìn)行初始化時(shí),其構(gòu)造函數(shù)鏈的所有構(gòu)造函數(shù)都被調(diào)用到,所以new操作符是很消耗系統(tǒng)資源的,new一個(gè)對(duì)象耗時(shí)往往是局部變量賦值耗時(shí)的上千倍。同時(shí),當(dāng)生成對(duì)象后,系統(tǒng)還要花時(shí)間進(jìn)行垃圾回收和處理。當(dāng)new創(chuàng)建對(duì)象不可避免時(shí),注意避免多次的使用new初始化一個(gè)對(duì)象。盡量在使用時(shí)再創(chuàng)建該對(duì)象,另外,應(yīng)該盡量重復(fù)使用一個(gè)對(duì)象,而不是聲明新的同類對(duì)象。一個(gè)重用對(duì)象的方法是改變對(duì)象的值,如可以通過(guò)setValue之類的方法改變對(duì)象的變量達(dá)到重用的目的。
4 選擇合適的方法調(diào)用:
在Java中,一切都是對(duì)象,如果有方法(Method)調(diào)用,處理器先要檢查該方法是屬于哪個(gè)對(duì)象,該對(duì)象是否有效,對(duì)象屬于什么類型,然后選擇合適的方法并調(diào)用。可以減少方法的調(diào)用,不影響可讀性等情況下,可以把幾個(gè)小的方法合成一個(gè)大的方法。另外,在方法前加上final,private關(guān)鍵字有利于編譯器的優(yōu)化。
5異常處理技巧
異常是Java的一種錯(cuò)誤處理機(jī)制,對(duì)程序來(lái)說(shuō)是非常有用的,但是異常對(duì)性能不利。拋出異常首先要?jiǎng)?chuàng)建一個(gè)新的對(duì)象,并進(jìn)行相關(guān)的處理,造成系統(tǒng)的開(kāi)銷,所以異常應(yīng)該用在錯(cuò)誤處理的情況,不應(yīng)該用來(lái)控制程序流程,流程盡量用while,if等處理。在不是很影響代碼健壯性的前提下,可以把幾個(gè)try/catch塊合成一個(gè)。
6 盡量使用局部變量
盡量使用局部變量,調(diào)用方法時(shí)傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時(shí)變量都保存在棧(Stack) 中,速度較快。其他變量,如靜態(tài)變量、實(shí)例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。
7同步處理技巧
同步主要出現(xiàn)在多線程的情況,為多線程同時(shí)運(yùn)行時(shí)提供對(duì)象數(shù)據(jù)安全的機(jī)制,多線程是比較復(fù)雜話題,應(yīng)用多線程也是為了獲得性能的提升,應(yīng)該盡可能減少同步。
另外,如果需要同步的地方,可以減少同步的代碼段,如只同步某個(gè)方法或函數(shù),而不是整個(gè)代碼。
8 盡可能的使用Java自身提供的API
Java的API一般都做了性能的考慮,如果完成相同的功能,優(yōu)先使用API而不是自己寫的代碼,如數(shù)組復(fù)制。
9 盡量減少I/O操作
輸入/輸出(I/O)包括很多方面,我們知道,進(jìn)行I/O操作是很消耗系統(tǒng)資源的。程序中應(yīng)該盡量少用I/O操作。使用時(shí)可以注意: . 合理控制輸出函數(shù)System.out.println()對(duì)于大多時(shí)候是有用的,特別是系統(tǒng)調(diào)試的時(shí)候,但也會(huì)產(chǎn)生大量的信息出現(xiàn)在控制臺(tái)和日志上,同時(shí)輸出時(shí),有序列化和同步的過(guò)程,造成了開(kāi)銷。
特別是在發(fā)行版中,要合理的控制輸出,可以在項(xiàng)目開(kāi)發(fā)時(shí),設(shè)計(jì)好一個(gè)Debug的工具類,在該類中可以實(shí)現(xiàn)輸出開(kāi)關(guān),輸出的級(jí)別,根據(jù)不同的情況進(jìn)行不同的輸出的控制。
10 盡量使用緩存
讀寫內(nèi)存要比讀寫硬盤上的文件要快很多,應(yīng)盡可能使用緩沖,以便直接從內(nèi)存中讀取數(shù)據(jù)。盡可能使用帶有Buffer的類代替沒(méi)有Buffer的類,如可以用BufferedReader 代替Reader,用BufferedWriter代替Writer來(lái)進(jìn)行處理I/O操作。
同樣可以用BufferedInputStream代替InputStream都可以獲得性能的提高
11 盡量不使用同步:
Servlet是多線程的,以處理不同的請(qǐng)求,基于前面同步的分析,如果有太多的同步就失去了多線程的優(yōu)勢(shì)了。
12 不用保存太多的信息在HttpSession中
很多時(shí)候,存儲(chǔ)一些對(duì)象在HttpSession中是有必要的,可以加快系統(tǒng)的開(kāi)發(fā),如網(wǎng)上商店系統(tǒng)會(huì)把購(gòu)物車信息保存在該用戶的Session中,但當(dāng)存儲(chǔ)大量的信息或是大的對(duì)象在會(huì)話中時(shí),是有害的,特別是當(dāng)系統(tǒng)中用戶的訪問(wèn)量很大,對(duì)內(nèi)存的需求就會(huì)很高。具體開(kāi)發(fā)時(shí),在這兩者之間應(yīng)作好權(quán)衡。
13清除SESSION:
通常情況,當(dāng)達(dá)到設(shè)定的超時(shí)時(shí)間時(shí),同時(shí)有些Session沒(méi)有了活動(dòng),服務(wù)器會(huì)釋放這些沒(méi)有活動(dòng)的Session,.. 不過(guò)這種情況下,特別是多用戶并訪時(shí),系統(tǒng)內(nèi)存要維護(hù)多個(gè)的無(wú)效Session。當(dāng)用戶退出時(shí),應(yīng)該手動(dòng)釋放,回收資源,實(shí)現(xiàn)如下:..
HttpSession theSession = request.getSession();
// 獲取當(dāng)前Session
if(theSession != null){
theSession.invalidate(); // 使該Session失效
}
14 緩存Home接口
EJB庫(kù)使用Enterprise Bean 的客戶端通過(guò)它的Home接口創(chuàng)建它的實(shí)例。客戶端能通過(guò)JNDI訪問(wèn)它。服務(wù)器通過(guò)Lookup方法來(lái)獲取。
JNDI是個(gè)遠(yuǎn)程對(duì)象,通過(guò)RMI方式調(diào)用,對(duì)它的訪問(wèn)往往是比較費(fèi)時(shí)的。所以,在設(shè)計(jì)時(shí)可以設(shè)計(jì)一個(gè)類專門用來(lái)緩存Home接口,在系統(tǒng)初始化時(shí)就獲得需要的Home接口并緩存,以后的引用只要引用緩存即可。
15 使用快速度的Jdbc驅(qū)動(dòng)
JDBC API包括兩種實(shí)現(xiàn)接口形式,一種是純Java實(shí)現(xiàn)的驅(qū)動(dòng),一種利用ODBC驅(qū)動(dòng)和數(shù)據(jù)庫(kù)客戶端實(shí)現(xiàn),具體有四種驅(qū)動(dòng)模式:
第一類:JDBC-ODBC橋,再加上ODBC驅(qū)動(dòng)程序。
JDBC驅(qū)動(dòng)程序是JDBC-ODBC橋再加上一個(gè)ODBC驅(qū)動(dòng)程序。建議第一類驅(qū)動(dòng)程序只用于原型開(kāi)發(fā),而不要用于正式的運(yùn)行環(huán)境。橋接驅(qū)動(dòng)程序由Sun提供,它的目標(biāo)是支持傳統(tǒng)的數(shù)據(jù)庫(kù)系統(tǒng)。Sun為該軟件提供關(guān)鍵問(wèn)題的補(bǔ)丁,但不為該軟件的最終用戶提供支持。一般地,橋接驅(qū)動(dòng)程序用于已經(jīng)在ODBC技術(shù)上投資的情形,例如已經(jīng)投資了Windows應(yīng)用服務(wù)器。
盡管Sun提供了JDBC-ODBC橋接驅(qū)動(dòng)程序,但由于ODBC會(huì)在客戶端裝載二進(jìn)制代碼和數(shù)據(jù)庫(kù)客戶端代碼,這種技術(shù)不適用于高事務(wù)性的環(huán)境。另外,第一類JDBC驅(qū)動(dòng)程序不支持完整的Java命令集,而是局限于ODBC驅(qū)動(dòng)程序的功能,這種驅(qū)動(dòng)方式也叫胖客戶,主要用于低并發(fā)請(qǐng)求,大數(shù)據(jù)量傳輸?shù)膽?yīng)用。
第二類:本機(jī)API,部分是Java的驅(qū)動(dòng)程序。
JDBC驅(qū)動(dòng)程序是本機(jī)API的部分Java代碼的驅(qū)動(dòng)程序,用于把JDBC調(diào)用轉(zhuǎn)換成主流數(shù)據(jù)庫(kù)API的本機(jī)調(diào)用。這類驅(qū)動(dòng)程序也存在與第一類驅(qū)動(dòng)程序一樣的性能問(wèn)題,即客戶端載入二進(jìn)制代碼的問(wèn)題,而且它們被綁定了特定的平臺(tái)。
第二類驅(qū)動(dòng)程序要求編寫面向特定平臺(tái)的代碼,主流的數(shù)據(jù)庫(kù)廠商,例如Oracle和IBM,都為它們的企業(yè)數(shù)據(jù)庫(kù)平臺(tái)提供了第二類驅(qū)動(dòng)程序,使用這些驅(qū)動(dòng)程序的開(kāi)發(fā)者必須及時(shí)跟進(jìn)不同數(shù)據(jù)庫(kù)廠商針對(duì)不同操作系統(tǒng)發(fā)行的各個(gè)驅(qū)動(dòng)程序版本。
另外,由于第二類驅(qū)動(dòng)程序沒(méi)有使用純Java的API,把Java應(yīng)用連接到數(shù)據(jù)源時(shí),往往必須執(zhí)行一些額外的配置工作。很多時(shí)候,第二類驅(qū)動(dòng)程序不能在體系結(jié)構(gòu)上與大型主機(jī)的數(shù)據(jù)源兼容;即使做到了兼容,效果也是比較差。
第三類:面向數(shù)據(jù)庫(kù)中間件的純Java驅(qū)動(dòng)程序。
JDBC驅(qū)動(dòng)程序是面向數(shù)據(jù)庫(kù)中間件的純Java驅(qū)動(dòng)程序,JDBC調(diào)用被轉(zhuǎn)換成一種中間件廠商的協(xié)議,中間件再把這些調(diào)用轉(zhuǎn)換到數(shù)據(jù)庫(kù)API。第三類JDBC驅(qū)動(dòng)程序的優(yōu)點(diǎn)是它以服務(wù)器為基礎(chǔ),也就是不再需要客戶端的本機(jī)代碼,這使第三類驅(qū)動(dòng)程序要比第一、二兩類快。另外,開(kāi)發(fā)者還可以利用單一的驅(qū)動(dòng)程序連接到多種數(shù)據(jù)庫(kù)。
第四類:直接面向數(shù)據(jù)庫(kù)的純Java驅(qū)動(dòng)程序。
JDBC驅(qū)動(dòng)程序是直接面向數(shù)據(jù)庫(kù)的純Java驅(qū)動(dòng)程序,即所謂的“瘦”(thin)驅(qū)動(dòng)程序,它把JDBC調(diào)用轉(zhuǎn)換成某種直接可被DBMS使用的網(wǎng)絡(luò)協(xié)議,這樣,客戶機(jī)和應(yīng)用服務(wù)器可以直接調(diào)用DBMS服務(wù)器。對(duì)于第四類驅(qū)動(dòng)程序,不同DBMS的驅(qū)動(dòng)程序不同。因此,在一個(gè)異構(gòu)計(jì)算環(huán)境中,驅(qū)動(dòng)程序的數(shù)量可能會(huì)比較多。但是,由于第四類驅(qū)動(dòng)程序具有較高的性能,能夠直接訪問(wèn)DBMS,所以這一問(wèn)題就不那么突出了, 這種驅(qū)動(dòng)方式,主要用于高并發(fā),低數(shù)據(jù)量請(qǐng)求的應(yīng)用中。
16 使用Jdbc鏈接池
為了提高訪問(wèn)數(shù)據(jù)庫(kù)的性能,我們還可以使用JDBC 2.0的一些規(guī)范和特性,JDBC是占用資源的,在使用數(shù)據(jù)庫(kù)連接時(shí)可以使用連接池Connection Pooling,避免頻繁打開(kāi)、關(guān)閉Connection。而我們知道,獲取Connection是比較消耗系統(tǒng)資源的。
Connection緩沖池:當(dāng)一個(gè)應(yīng)用程序關(guān)閉一個(gè)數(shù)據(jù)庫(kù)連接時(shí),這個(gè)連接并不真正釋放而是被循環(huán)利用,建立連接是消耗較大的操作,循環(huán)利用連接可以顯著的提高性能,因?yàn)榭梢詼p少新連接的建立。
一個(gè)通過(guò)DataSource獲取緩沖池獲得連接,并連接到一個(gè)CustomerDB數(shù)據(jù)源的代碼演示如下:
Context ctx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup("jdbc/CustomerDB");
Connection conn = dataSource.getConnection("password","username");
17 緩存DataSorce
一個(gè)DataSource對(duì)象代表一個(gè)實(shí)際的數(shù)據(jù)源。這個(gè)數(shù)據(jù)源可以是從關(guān)系數(shù)據(jù)庫(kù)到表格形式的文件,完全依賴于它是怎樣實(shí)現(xiàn)的,一個(gè)數(shù)據(jù)源對(duì)象注冊(cè)到JNDI名字服務(wù)后,應(yīng)用程序就可以從JNDI服務(wù)器上取得該對(duì)象,并使用之和數(shù)據(jù)源建立連接。
通過(guò)上面的例子,我們知道DataSource是從連接池獲得連接的一種方式,通過(guò)JNDI方式獲得,是占用資源的。
為了避免再次的JNDI調(diào)用,可以系統(tǒng)中緩存要使用的DataSource。
18 即時(shí)關(guān)閉使用過(guò)的資源
互聯(lián)網(wǎng)應(yīng)用系統(tǒng)一般是并發(fā)的系統(tǒng),在每次申請(qǐng)和使用完資源后,應(yīng)該釋放供別人使用,使用完成后應(yīng)該保證徹底的釋放。
19 架構(gòu)選型
CoreMediaCMS將整個(gè)應(yīng)用分成四成架構(gòu),每一層都可以獨(dú)立于其他層而正常運(yùn)行,每一層都可以分布式布署,極大的提高了應(yīng)用系統(tǒng)的穩(wěn)定性、可擴(kuò)展性、支持高并發(fā)的要求,每一次之前通過(guò)中間件Corba進(jìn)行穩(wěn)定的傳輸數(shù)據(jù)。
20 開(kāi)發(fā)框架的選型
充分利用開(kāi)源框架,可以大大提高開(kāi)發(fā)效率。很多初級(jí)開(kāi)發(fā)者,都采用DB+JavaBean+JSP這種初級(jí)的開(kāi)發(fā)模式,而現(xiàn)在主要使用Struts、Spring等MVC開(kāi)發(fā)框架。
常用開(kāi)發(fā)框架構(gòu)選型有:
Struts、Spring、Webwork等。
天極傳媒選擇的開(kāi)發(fā)框架是:Struts+Spring+iBatis,在這個(gè)開(kāi)發(fā)框架里,充分利用了Struts、Spring各自己的優(yōu)點(diǎn),可以選擇Stuts MVC,也可以選擇Spring MVC。
21 分級(jí)存儲(chǔ)
1)數(shù)據(jù)庫(kù)數(shù)據(jù)分級(jí)存儲(chǔ):
將經(jīng)常訪問(wèn)的數(shù)據(jù)和訪問(wèn)頻度低的數(shù)據(jù),分別存放到不同的分區(qū),甚至存放到不同的數(shù)據(jù)庫(kù)服務(wù)器,以便合進(jìn)分配硬盤I/O及系統(tǒng)I/O。
2)網(wǎng)站內(nèi)容發(fā)布之后,分級(jí)存儲(chǔ):
任何一個(gè)大型的網(wǎng)站,一般都有海量的內(nèi)容,為了提高訪問(wèn)效率,應(yīng)搭建分級(jí)存儲(chǔ)體系,根據(jù)應(yīng)用的重要性和訪問(wèn)并發(fā)要求,將這些內(nèi)容分級(jí)存儲(chǔ),同時(shí)將靜態(tài)內(nèi)容中的靜態(tài)頁(yè)面文件、圖片文件、下載文件分不同的Web服務(wù)器訪問(wèn),降低I/O爭(zhēng)用,提高訪問(wèn)效率,同時(shí)讓數(shù)據(jù)存儲(chǔ)、管理、備份更加清晰。
22 頁(yè)面靜態(tài)化
一個(gè)大型網(wǎng)站,既有靜態(tài)內(nèi)容,也有動(dòng)態(tài)內(nèi)容。靜態(tài)內(nèi)容,直接通過(guò)Apache或者Squid訪問(wèn),效率高,穩(wěn)定可靠,更多的是受服務(wù)器等硬件設(shè)備的I/O吞吐量、網(wǎng)絡(luò)環(huán)境及頁(yè)面代碼本身質(zhì)量限制,不受應(yīng)用系統(tǒng)及數(shù)據(jù)庫(kù)性能限制,這些內(nèi)容往往訪問(wèn)速度和效率不會(huì)有較大的問(wèn)題。
而動(dòng)態(tài)內(nèi)容,除了受硬件設(shè)備I/O、操作系統(tǒng)I/O及內(nèi)容、網(wǎng)絡(luò)環(huán)境及頁(yè)面代碼的影響,還要受應(yīng)用服務(wù)器和數(shù)據(jù)庫(kù)性能影響,因此,這部份內(nèi)容,要盡可能作靜態(tài)化或者偽靜態(tài),并采用緩存技術(shù),將其緩存,以減少對(duì)應(yīng)用服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器的操作次數(shù),提高用戶訪問(wèn)效率和穩(wěn)定性。
23 緩存策略
對(duì)于構(gòu)建的業(yè)務(wù)系統(tǒng),如果有些數(shù)據(jù)要經(jīng)常要從數(shù)據(jù)庫(kù)中讀取,同時(shí),這些數(shù)據(jù)又不經(jīng)常變化,這些數(shù)據(jù)就可以在系統(tǒng)中緩存起來(lái),使用時(shí)直接讀取緩存,而不用頻繁的訪問(wèn)數(shù)據(jù)庫(kù)讀取數(shù)據(jù)。
緩存工作可以在系統(tǒng)初始化時(shí)一次性讀取數(shù)據(jù),特別是一些只讀的數(shù)據(jù),當(dāng)數(shù)據(jù)更新時(shí)更新數(shù)據(jù)庫(kù)內(nèi)容,同時(shí)更新緩存的數(shù)據(jù)值。
例如:在CMS2005系統(tǒng)中,我們將很少發(fā)生變化的網(wǎng)站節(jié)點(diǎn)樹(shù)數(shù)據(jù),緩存在客戶端,當(dāng)用戶登錄時(shí),一次性讀入到客戶端緩存起來(lái),以后編輯在使用時(shí),不用再?gòu)臄?shù)據(jù)庫(kù)中讀取,大大提高了應(yīng)用系統(tǒng)的訪問(wèn)速度。
當(dāng)然,也可以將數(shù)據(jù)庫(kù)中重復(fù)訪問(wèn)的數(shù)據(jù)緩存在應(yīng)用服務(wù)器內(nèi)存中,減少對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)次數(shù),Java常用的緩存技術(shù)產(chǎn)品有:MemoryCache、OSCache等。