通常來講,性能經過如下幾個方面來表現:java
定量評測的性能指標:mysql
調優的層面算法
性能調優必須有明確的目標,不要爲了調優而調優,若是當前程序並無明顯的性能問題,盲目地進行調整,其風險可能遠遠大於收益。sql
1. 單例模式數據庫
對於系統的關鍵組件和被頻繁使用的對象,使用單例模式能夠有效地改善系統的性能數組
2. 代理模式緩存
代理模式能夠用來實現延遲加載,從而提高系統的性能和反應速度。安全
另外,能夠考慮使用動態代理的方式 。 動態代理的方法有: JDK自帶的動態代理, CGLIB, Javassist, 或ASM庫。網絡
3. 享元模式數據結構
好處:
1) 能夠節省重複建立對象的開銷
2) 對系統內存的需求減小
4. 裝飾者模式
實現性能組件與功能組件的完美分離
5. 觀察者模式
觀察者模式能夠用於事件監聽、通知發佈等場合。能夠確保觀察者在不使用輪詢監控的狀況下,及時收到相關的消息和事件。
6. Value Object 模式
將一個對象的各個屬性進行封裝,將封裝後的對象在網絡中傳遞,從而使系統擁有更好的交互模型,而且減小網絡通訊數據,從而提升系統性能。
7. 業務代理模式
將一組由遠程方法調用構成的業務流程,封裝在一個位於展現層的代理類中。
思考:
單例模式, 工廠模式和享元模式的差別?
1.緩衝
I/O 操做很容易成爲性能瓶頸,因此,儘量在 I/O 讀寫中加入緩衝組件,以提升系統的性能。
2. 緩存
緩存能夠保存一些來之不易的數據或者計算結果,當須要再次使用這些數據時,能夠從緩存中低成本地獲取,而不須要再佔用寶貴的系統資源。
Java緩存框架:
EHCache, OSCache,JBossCache
3. 對象複用 -- "池"
最熟悉的線程池和數據庫鏈接池。
目前應用較爲普遍的數據庫鏈接池組件有C3P0 和Proxool.
4.並行替代串行
5. 負載均衡
跨JVM虛擬機,專門用於分佈式緩存的框架--Terracotta, 使用Terracotta能夠實現Tomcat的Session共享。
6. 時間換空間
7. 空間換時間
1. 字符串優化處理
1)
2) subString() 方法的內存泄漏
若是原字串很長,截取的字串卻有比較短,使用如下方式返回:
3) 字符串分割和查找
可使用的方法:
split()方法 -- 最慢, 寫法簡單
StringTokenizer 方法 -- 較快,寫法通常
indexOf()和subString() 方法 - 最快, 寫法麻煩
4) 使用ChartAt 代替 startsWith 和 endsWith
性能要求比較高時,可使用這條。
5) StringBuffer 和 StringBuilder
String result = "String" + "and" + "string"+"append";
這段看起來性能不高的代碼在實際執行時反而會比StringBuilder 來的快。
緣由是Java 編譯器自己會作優化。
可是不能徹底依靠編譯器的優化, 仍是建議顯示地使用StringBuffer 或StringBuffer對象來提高系統性能。
StringBuffer 和 StringBuilder 的差別是:
StingBuffer 幾乎全部的方法都作了同步
StringBuilder 並無任何同步。
因此StringBuilder 的效率好於StringBuffer, 可是在多線程系統中,StringBuilder 沒法保證線程安全。
另外,預先評估StringBuilder 的大小,能提高系統的性能。
2. 核心數據結構
1) List 接口
3種List實現: ArrayList, Vector, 和LinkedList
ArrayList 和Vector 使用了數組實現, Vector 絕大部分方法都作了線程同步, ArrayList 沒有對任何一個方法作線程同步。(ArrayList 和Vector 看上去性能相差無幾)
使用LinkedList 對堆內存和GC的要求更高。
若是在系統應用中, List對象須要常常在任意位置插入元素,則能夠考慮使用LinkedList 替代ArrayList
對於ArrayList從尾部刪除元素時效率很高,從頭部刪除元素時至關費時,
而LinkedList 從頭尾刪除元素時效率相差無幾,可是從中間刪除元素時性能很是槽糕。
頭部 | 中間 | 尾部 | |
ArrayList | 6203 | 3125 | 16 |
LinkedList | 15 | 8781 | 16 |
List 遍歷操做
ForEach | 迭代器 | for 循環 | |
ArrayList | 63 | 47 | 31 |
LinkedList | 63 | 47 | 無窮大 |
2) Map 接口
實現類有: Hashtable, HashMap, LinkedHashMap和TreeMap
HashTable 和HashMap 的差別
HashTable大部分方法作了同步, HashTable 不容許key或者Value 使用null值;(性能上看起來無明顯差別)
3) Set 接口
4) 優化集合訪問代碼
1. 分離循環中被重複調用的代碼
for(int i=0;i<collection.size();i++)
替換成
int count = collection.size();
for(int i=0;i<count;i++)
5). RandomAccess接口
3. 使用NIO 提高性能
在Java 的標準I/O中, 提供了基於流的I/O 實現, 即InputStream 和 OutputStream. 這種基於流的實現是以字節爲單位處理數據, 而且很是容易創建各類過濾器。
NIO是 New I/O 的簡稱, 與舊式的基於流的 I/O 方法相對, 它表示新的一套Java I/O 標準。是在java 1.4 中被歸入到JDK中的, 特性有
- 爲全部的原始類型提供 Buffer 緩存支持
- 使用Java.nio.charset.Charset 做爲字符集編碼解碼解決方案
- 增長通道對象(Channel), 做爲新的原始I/O 抽象
- 支持鎖和內存映射文件的文件訪問接口
- 提供了基於Selector 的異步網絡I/O
與流式的I/O 不一樣, NIO 是基於塊(Block 的), 它以塊爲基本單位處理數據。
4. 引用類型。
強引用、軟引用、弱引用和虛引用
強引用:
a)強引用能夠直接訪問目標對象
b) 強引用所指向的對象在任什麼時候候都不會被系統回收
c)強引用可能致使內存泄漏
軟引用:
軟引用能夠經過java.lang.ref.SoftReference來使用。 一個持有軟引用的對象,不會被JVM很快回收, JVM會根據當前的使用情況來判斷什麼時候回收.當堆使用率臨近閾值時,纔會去回收軟引用的對象。只要有足夠的內存,軟引用即可能在內存中存活相對長一段時間。所以,軟引用能夠用於實現對內存敏感的Cache.
弱引用:
在系統GC時,只要發現弱引用,無論系統堆空間是否足夠,都會將對象進行回收。
虛引用
一個持有虛引用的對象,和沒有引用幾乎是同樣的,隨時均可能被垃圾回收器回收。但試圖經過虛引用的get()方法去跌強引用時,老是會失敗。而且,虛引用必須和引用隊列一塊兒使用,它的做用在於跟蹤回收過程。
WeakHashMap類及其實現
WeakHashMap 是弱引用的一種典型應用,它能夠做爲簡單的緩存表解決方案。
1. 慎用異常
try catch 應用與循環體以外
2. 使用局部變量
調用方法時傳遞的參數以及在調用中建立的臨時變量都保存在棧中,速度較快。
其餘變量,如靜態變量、實例變量等,都在堆中建立,速度較慢。
局部變量的訪問速度遠遠高於類的成員變量。
3. 位運算代替乘除法
4. 替換Switch .
這一條應該注意的是一個新的思路問題, 使用不一樣的方式代替switch 語句。
這裏的例子性能測試起來, switch 的性能反而更好一些。
5. 一維數組代替二維數組
直接看例子:
一維數字用的時間少了不少。
6. 提取表達式
有些重複運算的部分能夠提取出來。
7. 展開循環
展開循環是一種在極端狀況下使用的優化手段,由於展開循可能會影響代碼的可讀性和可維護性, 因此取捨之間, 就要根據實際情況來看了。
看例子:
8. 布爾運算代替位運算
雖然位運算的速度遠遠高於算術運算,可是在條件判斷時,使用位運算替代布爾運算倒是很是錯誤的選擇。
對於"a&&b&&c", 只要有一項返回 false, 整個表達式就返回 false.
9. 使用 arrayCopy()
Java API 提升了數組複製的高效方法: arrayCopy().
這個函數是 native 函數, 一般native 函數的性能要優於普通的函數, 僅出於性能考慮, 在軟件開發時, 應儘量調用native 函數。
10. 使用 Buffer 進行 I/O 操做
除NIO 外, 使用Java 進行I/O 操做有兩種基本方式
1. 使用基於InputStream 和 OutoutStream的方式
2. 使用Writer 和Reader
不管使用哪一種方式進行文件I/O , 若是能合理地使用緩衝, 就能有效提升I/O 的性能
11. 使用clone() 代替new
對於重量級對象, 優於對象在構造函數中可能會進行一些複雜且耗時額操做, 所以, 構造函數的執行時間可能會比較長。Object.clone() 方法能夠繞過對象構造函數, 快速複製一個對象實例。因爲不須要調用對象構造函數, 所以, clone 方法不會受到構造函數性能的影響, 快速生成一個實例。
12. 靜態方法替代實例方法
使用static 關鍵字描述的方法爲靜態方法, 在Java 中, 優於實例方法須要維護一張相似虛函數表的結構,以實現對多態的支持。 與靜態方法相比, 實例方法的調用須要更多的資源。 所以,對於一些經常使用的工具類方法,沒有對其進行重載的必要,那麼將它們聲明爲static, 即可以加速方法的調用。