11 個簡單的 Java 性能調(diào)優(yōu)技巧

大多數(shù)開發(fā)人員理所當(dāng)然地以為性能優(yōu)化很復(fù)雜怯屉,需要大量的經(jīng)驗和知識抛猫。好吧,不能說這是完全錯誤的刃泡。優(yōu)化應(yīng)用程序以獲得最佳性能不是一件容易的事情巧娱。但是,這并不意味著如果你不具備這些知識烘贴,就不能做任何事情禁添。這里有11個易于遵循的建議和最佳實踐可以幫助你創(chuàng)建一個性能良好的應(yīng)用程序。

image.png

大部分建議是針對Java的桨踪。但也有若干建議是與語言無關(guān)的老翘,可以應(yīng)用于所有應(yīng)用程序和編程語言。在討論專門針對Java的性能調(diào)優(yōu)技巧之前,讓我們先來看看通用技巧铺峭。

1.在你知道必要之前不要優(yōu)化

這可能是最重要的性能調(diào)整技巧之一墓怀。你應(yīng)該遵循常見的最佳實踐做法并嘗試高效地實現(xiàn)用例。但是卫键,這并不意味著在你證明必要之前傀履,你應(yīng)該更換任何標(biāo)準(zhǔn)庫或構(gòu)建復(fù)雜的優(yōu)化。

在大多數(shù)情況下莉炉,過早優(yōu)化不但會占用大量時間钓账,而且會使代碼變得難以閱讀和維護(hù)。更糟糕的是呢袱,這些優(yōu)化通常不會帶來任何好處官扣,因為你花費大量時間來優(yōu)化的是應(yīng)用程序的非關(guān)鍵部分翅敌。

那么羞福,你如何證明你需要優(yōu)化一些東西呢?

首先蚯涮,你需要定義應(yīng)用程序代碼的速度得多快治专,例如,為所有API調(diào)用指定最大響應(yīng)時間遭顶,或者指定在特定時間范圍內(nèi)要導(dǎo)入的記錄數(shù)量张峰。在完成這些之后,你就可以測量應(yīng)用程序的哪些部分太慢需要改進(jìn)棒旗。然后喘批,接著看第二個技巧。

2.使用分析器查找真正的瓶頸

在你遵循第一個建議并確定了應(yīng)用程序的某些部分需要改進(jìn)后铣揉,那么從哪里開始呢饶深?

你可以用兩種方法來解決問題:

  • 查看你的代碼,并從看起來可疑或者你覺得可能會產(chǎn)生問題的部分開始逛拱。
  • 或者使用分析器并獲取有關(guān)代碼每個部分的行為和性能的詳細(xì)信息敌厘。

希望不需要我解釋為什么應(yīng)該始終遵循第二種方法的原因。

很明顯朽合,基于分析器的方法可以讓你更好地理解代碼的性能影響俱两,并使你能夠?qū)W⒂谧铌P(guān)鍵的部分。如果你曾使用過分析器曹步,那么你一定記得曾經(jīng)你是多么驚訝于一下就找到了代碼的哪些部分產(chǎn)生了性能問題宪彩。老實說,我第一次的猜測不止一次地導(dǎo)致我走錯了方向讲婚。

3.為整個應(yīng)用程序創(chuàng)建性能測試套件

這是另一個通用技巧尿孔,可以幫助你避免在將性能改進(jìn)部署到生產(chǎn)后經(jīng)常會發(fā)生的許多意外問題。你應(yīng)該總是定義一個測試整個應(yīng)用程序的性能測試套件,并在性能改進(jìn)之前和之后運行它纳猫。

這些額外的測試運行將幫助你識別更改的功能和性能副作用婆咸,并確保不會導(dǎo)致弊大于利的更新。如果你工作于被應(yīng)用程序若干不同部分使用的組件芜辕,如數(shù)據(jù)庫或緩存尚骄,那么這一點就尤其重要。

4.首先處理最大的瓶頸

在創(chuàng)建測試套件并使用分析器分析應(yīng)用程序之后侵续,你可以列出一系列需要解決以提高性能的問題倔丈。這很好,但它仍然不能回答你應(yīng)該從哪里開始的問題状蜗。你可以專注于速效方案需五,或從最重要的問題開始。

速效方案一開始可能會很有吸引力轧坎,因為你可以很快顯示第一個成果宏邮。但有時,可能需要你說服其他團(tuán)隊成員或管理層認(rèn)為性能分析是值得的——因為暫時看不到效果缸血。

但總的來說蜜氨,我建議首先處理最重要的性能問題。這將為你提供最大的性能改進(jìn)捎泻,而且可能再也不需要去解決其中一些為了滿足性能需求的問題飒炎。

常見的性能調(diào)整技巧到此結(jié)束。下面讓我們仔細(xì)看看一些特定于Java的技巧笆豁。

5.使用StringBuilder以編程方式連接String

有很多不同的選項來連接Java中的String郎汪。例如,你可以使用簡單的+或+ =闯狱,以及StringBuffer或StringBuilder煞赢。

那么,你應(yīng)該選擇哪種方法扩氢?

答案取決于連接String的代碼耕驰。如果你是以編程方式添加新內(nèi)容到String中,例如在for循環(huán)中录豺,那么你應(yīng)該使用StringBuilder朦肘。它很容易使用,并提供比StringBuffer更好的性能双饥。但請記住媒抠,與StringBuffer相比,StringBuilder不是線程安全的咏花,可能不適合所有用例趴生。

你只需要實例化一個新的StringBuilder并調(diào)用append方法來向String中添加一個新的部分阀趴。在你添加了所有的部分之后,你就可以調(diào)用toString()方法來檢索連接的String苍匆。

下面的代碼片段顯示了一個簡單的例子刘急。在每次迭代期間,這個循環(huán)將i轉(zhuǎn)換為一個String浸踩,并將它與一個空格一起添加到StringBuilder sb中叔汁。所以,最后检碗,這段代碼將在日志文件中寫入“This is a test0 1 2 3 4 5 6 7 8 9”据块。

StringBuilder sb = new StringBuilder(“This is a test”);
for (int i=0; i<10; i++) {
    sb.append(i);
    sb.append(” “);
}
log.info(sb.toString());

正如在代碼片段中看到的那樣,你可以將String的第一個元素提供給構(gòu)造方法折剃。這將創(chuàng)建一個新的StringBuilder另假,新的StringBuilder包含提供的String和16個額外字符的容量。當(dāng)你向StringBuilder添加更多字符時怕犁,JVM將動態(tài)增加StringBuilder的大小边篮。

如果你已經(jīng)知道你的String將包含多少個字符,則可以將該數(shù)字提供給不同的構(gòu)造方法以實例化具有定義容量的StringBuilder因苹。這進(jìn)一步提高了效率苟耻,因為它不需要動態(tài)擴展其容量篇恒。

6.使用+連接一個語句中的String

當(dāng)你用Java實現(xiàn)你的第一個應(yīng)用程序時扶檐,可能有人告訴過你不應(yīng)該用+來連接String。如果你是在應(yīng)用程序邏輯中連接字符串胁艰,這是正確的款筑。字符串是不可變的,每個字符串的連接結(jié)果都存儲在一個新的String對象中腾么。這需要額外的內(nèi)存奈梳,會減慢你的應(yīng)用程序,特別是如果你在一個循環(huán)內(nèi)連接多個字符串的話解虱。

在這些情況下攘须,你應(yīng)該遵循技巧5并使用StringBuilder。

但是殴泰,如果你只是將字符串分成多行來改善代碼的可讀性于宙,那情況就不一樣了。

Query q = em.createQuery(“SELECT a.id, a.firstName, a.lastName ”
+ “FROM Author a ”
+ “WHERE a.id = :id”);

在這些情況下悍汛,你應(yīng)該用一個簡單的+來連接你的字符串捞魁。Java編譯器會對此優(yōu)化并在編譯時執(zhí)行連接。所以离咐,在運行時谱俭,你的代碼將只使用1個String,不需要連接。

7.盡可能使用基元

避免任何開銷并提高應(yīng)用程序性能的另一個簡便而快速的方法是使用基本類型而不是其包裝類昆著。所以县貌,最好使用int來代替Integer,使用double來代替Double凑懂。這允許JVM將值存儲在堆棧而不是堆中以減少內(nèi)存消耗窃这,并作出更有效的處理。

8.試著避免BigInteger和BigDecimal

既然我們在討論數(shù)據(jù)類型征候,那么我們也快速瀏覽一下BigInteger和BigDecimal吧杭攻。尤其是后者因其精確性而受到大家的歡迎。但是這是有代價的疤坝。

BigInteger和BigDecimal比簡單的long或double需要更多的內(nèi)存兆解,并且會顯著減慢所有計算。所以跑揉,你如果需要額外的精度锅睛,或者數(shù)字將超過long的范圍,那么最好三思而后行历谍。這可能是你需要更改以解決性能問題的唯一方法现拒,特別是在實現(xiàn)數(shù)學(xué)算法的時候。

9.首先檢查當(dāng)前日志級別

這個建議應(yīng)該是顯而易見的望侈,但不幸的是印蔬,很多程序員在寫代碼的時候都會大多會忽略它。在你創(chuàng)建調(diào)試消息之前脱衙,始終應(yīng)該首先檢查當(dāng)前日志級別侥猬。否則,你可能會創(chuàng)建一個之后會被忽略的日志消息字符串捐韩。

這里有兩個反面例子退唠。

// don’t do this
log.debug(“User [” + userName + “] called method X with [” + i + “]”);
// or this
log.debug(String.format(“User [%s] called method X with [%d]”, userName, i));

在上面兩種情況中,你都將執(zhí)行創(chuàng)建日志消息所有必需的步驟荤胁,在不知道日志框架是否將使用日志消息的前提下瞧预。因此在創(chuàng)建調(diào)試消息之前,最好先檢查當(dāng)前的日志級別仅政。

// do this
if (log.isDebugEnabled()) {
    log.debug(“User [” + userName + “] called method X with [” + i + “]”);
}

10.使用Apache CommonsStringUtils.Replace而不是String.replace

一般來說垢油,String.replace方法工作正常,效率很高已旧,尤其是在使用Java 9的情況下秸苗。但是,如果你的應(yīng)用程序需要大量的替換操作运褪,并且沒有更新到最新的Java版本惊楼,那么我們依然有必要查找更快和更有效的替代品玖瘸。

有一個備選答案是Apache Commons Lang的StringUtils.replace方法。正如Lukas Eder在他最近的一篇博客文章中所描述的檀咙,StringUtils.replace方法遠(yuǎn)勝Java 8的String.replace方法雅倒。

而且它只需要很小的改動。即添加Apache Commons Lang項目的Maven依賴項到應(yīng)用程序pom.xml中弧可,并將String.replace方法的所有調(diào)用替換為StringUtils.replace方法蔑匣。

// replace this
test.replace(“test”, “simple test”);
// with this
StringUtils.replace(test, “test”, “simple test”);

11.緩存昂貴的資源,如數(shù)據(jù)庫連接

緩存是避免重復(fù)執(zhí)行昂貴或常用代碼片段的流行解決方案棕诵〔昧迹總的思路很簡單:重復(fù)使用這些資源比反復(fù)創(chuàng)建新的資源要便宜。

一個典型的例子是緩存池中的數(shù)據(jù)庫連接校套。新連接的創(chuàng)建需要時間价脾,如果你重用現(xiàn)有連接,則可以避免這種情況笛匙。

你還可以在Java語言本身找到其他例子侨把。例如,Integer類的valueOf方法緩存了-128到127之間的值妹孙。你可能會說創(chuàng)建一個新的Integer并不是太昂貴秋柄,但是由于它經(jīng)常被使用,以至于緩存最常用的值也可以提供性能優(yōu)勢蠢正。

但是骇笔,當(dāng)你考慮緩存時,請記住緩存實現(xiàn)也會產(chǎn)生開銷机隙。你需要花費額外的內(nèi)存來存儲可重用資源蜘拉,因此你可能需要管理緩存以使資源可訪問,以及刪除過時的資源。

所以贰健,在開始緩存任何資源之前篮撑,請確保實施緩存是值得的,也就是說必須足夠多地使用它們氨淌。

總結(jié)

正如你所看到的,有時不需要太多工作就可以提高應(yīng)用程序的性能。本文中的大部分建議只需要你稍作努力就可以將它們應(yīng)用于你的代碼娱俺。

但是,最重要的還是那些與是什么編程語言無關(guān)的技巧:

  • 在你知道必要之前不要優(yōu)化
  • 使用分析器查找真正的瓶頸
  • 首先處理最大的瓶頸

歡迎加入學(xué)習(xí)交流群569772982废麻,大家一起學(xué)習(xí)交流荠卷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市烛愧,隨后出現(xiàn)的幾起案子油宜,更是在濱河造成了極大的恐慌掂碱,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慎冤,死亡現(xiàn)場離奇詭異疼燥,居然都是意外死亡,警方通過查閱死者的電腦和手機蚁堤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門醉者,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人披诗,你說我怎么就攤上這事撬即。” “怎么了呈队?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵搞莺,是天一觀的道長。 經(jīng)常有香客問我掂咒,道長才沧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任绍刮,我火速辦了婚禮温圆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孩革。我一直安慰自己,他們只是感情好膝蜈,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饱搏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪推沸。 梳的紋絲不亂的頭發(fā)上备绽,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音肺素,去河邊找鬼。 笑死倍靡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的课舍。 我是一名探鬼主播塌西,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼他挎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了雇盖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤崔挖,失蹤者是張志新(化名)和其女友劉穎庵寞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐川,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年瘸右,在試婚紗的時候發(fā)現(xiàn)自己被綠了岩齿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡龄章,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出做裙,到底是詐尸還是另有隱情肃晚,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布陷揪,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏耐量。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一趴拧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧著榴,春花似錦、人聲如沸脑又。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至席舍,卻和暖如春哮笆,著一層夾襖步出監(jiān)牢的瞬間来颤,已是汗流浹背稠肘。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留本讥,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓拷沸,卻偏偏與公主長得像薯演,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子跨扮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理衡创,服務(wù)發(fā)現(xiàn),斷路器璃氢,智...
    卡卡羅2017閱讀 134,716評論 18 139
  • 大家在寫代碼的時候是不是都只考慮了實現(xiàn),沒有考慮性能呢一也?如果說你只是做業(yè)務(wù)系統(tǒng)的增刪改查并且業(yè)務(wù)量不大的話喉脖。這是毋...
    cnJason閱讀 397評論 0 2
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法抑月,類相關(guān)的語法,內(nèi)部類的語法题诵,繼承相關(guān)的語法,異常的語法仇轻,線程的語...
    子非魚_t_閱讀 31,667評論 18 399
  • 煙雨朦朧中有一花布傘奶甘,傘外是煙雨婆娑、風(fēng)貫滿樓臭家,傘內(nèi)是那佳人,遺世獨立钉赁、娥眉微躇;傘外的雨淅淅瀝瀝你踩,傘內(nèi)的人婷婷玉...
    c4e30b19f233閱讀 373評論 0 1
  • inode 是 UNIX 操作系統(tǒng)中的一種數(shù)據(jù)結(jié)構(gòu)带膜,其本質(zhì)是結(jié)構(gòu)體吩谦,它包含了與文件系統(tǒng)中各個文件相關(guān)的一些重要信息...
    StarShift閱讀 288評論 0 0