首頁 > Java > Java面試題 > 主體

面試:你知道Java效能優化有哪些手段?

發布: 2023-08-16 16:49:14
轉載
794 人瀏覽過

前兩天,一位群組裡的朋友找我聊,面試中被問到效能優化手段該如何回答,今天我們就聊聊。 本文主要著重於理論分析,我們從整體來看 Java 效能最佳化都有哪些可以遵循的規律。

本文主講理論,關於實踐,後續的文章會用較多的案例來細化本文的知識點,適合反复思考與歸納

概述

效能最佳化根據最佳化的類別,分為業務最佳化和技術最佳化。業務優化所產生的效果也是非常大的,但它屬於產品和管理的範疇。同作為程式設計師,在平常工作中,我們面對的最佳化方式,主要是透過一系列的技術手段,來完成對既定的最佳化目標。這一系列的技術手段,我大體歸納為如圖以下 7 類:

面試:你知道Java效能優化有哪些手段?

#可以看到,優化方式集中在計算資源和儲存資源的規劃。優化方法有多種用空間換時間的方式,但只照顧計算速度,而不考慮複雜性和空間問題,也是不可取的。我們要做的,就是在照顧性能的前提下,要達到資源利用的最適狀態。

接下來,我簡單介紹一下這7個最佳化方向。如果你覺得比較枯燥,那也沒關係,我們這篇文章的目的,就是讓你的腦海裡有一個總分的概念,以及對理論基礎有一個整體的認識。

復用最佳化

#在寫程式碼的時候,你會發現有很多重複的程式碼可以提取出來,做成公共的方法。這樣,下次用的時候,就不用再費勁寫一遍了。

這種想法就是複用。上面的描述是編碼邏輯上的最佳化,對於資料存取來說,有相同的複用情況。無論是在生活中或編碼中,重複的事情一直在發生,如果沒有重複使用,工作和生活就會比較累。

在軟體系統中,談到資料重複使用,我們首先想到的就是緩衝和快取。注意這兩個字的區別,它們的意義是完全不同的,很多同學很容易搞混,在這裡簡單地介紹一下。

緩衝(Buffer),常見於資料的暫存,然後批次傳輸或寫入。多使用順序方式,用來緩解不同設備之間頻繁地、緩慢地隨機寫,緩衝主要針對的是寫入操作。

快取(Cache),常見於對已讀取資料的複用,透過將它們快取在相對高速的區域,快取主要針對的是讀取操作。

與之類似的,是對於物件的池化操作,例如資料庫連線池、執行緒池等,在 Java 中使用得非常頻繁。由於這些物件的創建和銷毀成本都比較大,我們在使用之後,也會將這部分物件暫時存儲,下次用的時候,就不用再走一遍耗時的初始化操作了。

計算最佳化

#並行執行

##現在的CPU 發展速度很快,絕大多數硬件,都是多核心。要加快某個任務的執行,最快最優的解決方式,就是讓它並行執行。並行執行有以下三種模式。

第一種模式是多機,採用負載平衡的方式,將流量或大的計算拆分成多個部分,同時進行處理。例如,Hadoop 透過 MapReduce 的方式,把任務打散,多機同時進行運算。

第二種模式是採用多進程。例如 Nginx,採用 NIO 程式設計模型,Master 統一管理 Worker 進程,然後由 Worker 進程進行真正的請求代理,這也能很好地利用硬體的多個 CPU。

第三種模式是使用多線程,這也是 Java 程式設計師接觸最多的。例如 Netty,採用 Reactor 程式設計模型,同樣使用 NIO,但它是基於執行緒的。 Boss 執行緒用來接收請求,然後調度給對應的 Worker 執行緒進行真正的業務運算。

###像Golang 這樣的語言,有更輕量級的協程(Coroutine),協程是一種比線程更加輕量級的存在,但目前在Java 中還不太成熟,就不做太多介紹了,但本質上,它也是對於多核心的應用,使得任務並行執行。 ###

變同步為非同步

#再一種對於計算的最佳化,就是變同步為非同步,這通常涉及程式設計模型的改變。同步方式,請求會一直阻塞,直到有成功,或失敗結果的回傳。雖然它的程式模型簡單,但應對突發的、時間段傾斜的流量,問題就特別大,請求很容易失敗。

非同步操作可以方便地支援橫向擴容,也可以緩解瞬時壓力,使請求變得平滑。同步請求,就像拳頭打在鋼板上;非同步請求,就像拳頭打在海綿上。你可以想像一下這個過程,後者肯定是富有彈性的,體驗更加友善。

惰性載入

#最後一種,就是使用一些常見的設計模式來優化業務,提升體驗,例如單例模式、代理模式等。舉個例子,在繪製 Swing 視窗的時候,如果要顯示比較多的圖片,就可以先載入一個佔位符,然後透過後台執行緒慢慢載入所需的資源,這就可以避免視窗的僵死。

結果集最佳化

#接下來介紹對結果集的最佳化。舉個比較直觀的例子,我們都知道 XML 的表現形式是非常好的,那為什麼還有 JSON 呢?除了書寫要簡單一些,一個重要的原因就是它的體積變小了,傳輸效率和解析效率變高了,像 Google 的 Protobuf,體積就更小了一些。雖然可讀性降低,但在一些高並發場景下(如 RPC),能夠顯著提高效率,這是典型的對結果集的最佳化。

這是由於我們目前的 Web 服務,都是 C/S 模式。資料從伺服器傳輸到客戶端,需要分發多份,這個資料量是急劇膨脹的,每減少一小部分存儲,都會有比較大的傳輸性能和成本提升。

像 Nginx,一般都會開啟 GZIP 壓縮,使得傳輸的內容保持緊湊。客戶端只需要一小部分運算能力,就可以方便解壓。由於這個操作是分散的,所以性能損失是固定的。

了解了這個道理,我們就能看到對於結果集優化的一般思路,你要盡量保持回傳資料的精簡。一些客戶端不需要的字段,那就在程式碼中,或直接在 SQL 查詢中,就把它去掉。

對於某些對時效性要求不高,但對處理能力有高要求的業務。我們要吸收緩衝區的經驗,盡量減少網路連線的交互,採用批量處理的方式,增加處理速度。

結果集合很可能會有二次使用,你可能會把它加入快取中,但依然在速度上有所欠缺。這個時候,就需要對資料集合進行處理最佳化,採用索引或 Bitmap 點陣圖等方式,加快資料存取速度。

資源衝突最佳化

我們在平常的開發中,會牽涉到很多共享資源。這些共享資源,有的是單機的,例如一個 HashMap;有的是外部存儲,例如一個資料庫行;有的是單一資源,例如 Redis 某個 key 的Setnx;有的是多個資源的協調,例如事務、分散式事務等。

現實中的效能問題,和鎖定相關的問題是非常多的。大多數我們會想到資料庫的行鎖、表鎖、Java 中的各種鎖等。在更底層,例如 CPU 指令層級的鎖、JVM 指令層級的鎖、作業系統內部鎖等,可以說無所不在。

只有並發,才能產生資源衝突。也就是在同一時刻,只能有一個處理請求能夠取得到共享資源。解決資源衝突的方式,就是加鎖。再比如事務,在本質上也是一種鎖。

依照鎖級別,鎖可分為樂觀鎖和悲觀鎖,樂觀鎖在效率上肯定是更高一些;按照鎖類型,鎖又分為公平鎖和非公平鎖,在對任務的調度上,有一些細微的差別。

對資源的爭用,會造成嚴重的效能問題,所以會有一些針對無鎖佇列之類的研究,對效能的提升也是巨大的。

演算法最佳化

#演算法能夠顯著提高複雜業務的效能,但在實際的業務中,往往都是變種。由於儲存越來越便宜,在一些 CPU 非常緊張的業務中,往往採用空間換取時間的方式,來加快處理速度。

演算法屬於程式碼調優,程式碼調優涉及許多編碼技巧,需要使用者對所使用語言的 API 也非常熟悉。有時候,對演算法、資料結構的靈活使用,也是程式碼最佳化的重要內容。例如,常用的降低時間複雜度的方式,就有遞歸、二分、排序、動態規劃等。

一个优秀的实现,比一个拙劣的实现,对系统的影响是非常大的。比如,作为 List 的实现,LinkedList 和 ArrayList 在随机访问的性能上,差了好几个数量级;又比如,CopyOnWriteList 采用写时复制的方式,可以显著降低读多写少场景下的锁冲突。而什么时候使用同步,什么时候是线程安全的,也对我们的编码能力有较高的要求。

这部分的知识,就需要我们在平常的工作中注意积累,后面的课时中,也会挑比较重要的知识点穿插讲解。

高效实现

在平时的编程中,尽量使用一些设计理念良好、性能优越的组件。比如,有了 Netty,就不用再选择比较老的 Mina 组件。而在设计系统时,从性能因素考虑,就不要选 SOAP 这样比较耗时的协议。再比如,一个好的语法分析器(比如使用 JavaCC),其效率会比正则表达式高很多。

总之,如果通过测试分析,找到了系统的瓶颈点,就要把关键的组件,使用更加高效的组件进行替换。在这种情况下,适配器模式是非常重要的。这也是为什么很多公司喜欢在现有的组件之上,再抽象一层自己的;而当在底层组件进行切换的时候,上层的应用并无感知。

JVM 优化

因为 Java 是运行在 JVM 虚拟机之上,它的诸多特性,就要受到 JVM 的制约。对 JVM 虚拟机进行优化,也能在一定程度上能够提升 JAVA 程序的性能。如果参数配置不当,甚至会造成 OOM 等比较严重的后果。

目前被广泛使用的垃圾回收器是 G1,通过很少的参数配置,内存即可高效回收。CMS 垃圾回收器已经在 Java 14 中被移除,由于它的 GC 时间不可控,有条件应该尽量避免使用。

JVM 性能调优涉及方方面面的取舍,往往是牵一发而动全身,需要全盘考虑各方面的影响。所以了解 JVM 内部的一些运行原理,还是特别重要的,它有益于我们加深对代码更深层次的理解,帮助我们书写出更高效的代码。

小结

以上就是代码优化的 7 个大方向,我们通过简要的介绍,让大家对性能优化的内容有了大体的了解。这7大方向是代码优化的最主要方向,当然,性能优化还包含数据库优化、操作系统优化、架构优化等其他一些内容,这些不是我们的重点,在后面的文章中,我们也只做简要的介绍。

以上是面試:你知道Java效能優化有哪些手段?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:Java后端技术全栈
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!