《阿里巴巴Java工做手冊》學習筆記

最近瀏覽了一下阿里巴巴的Java開發手冊,感受內容確實很是的贊,發現了很多本身在編程中的誤區,所以決定經過成文牢固掌握,文中將選取我的認爲比較重要的部分進行描述與分析。」願站在巨人的肩膀上,碼出高效,碼出質量「前端

概述

手冊中內容不少,包括編碼規約、工程結構、MySQL數據庫、異常日誌、安全規約、單元測試等6大部分。其中工程結構部分在總體上對項目進行了把控,編碼規約和MySQL設計規約中有很是多的「最佳實踐」,我的認爲是最爲有價值的部分。次重點安全規約很符合互聯網場景的須要,異常日誌和單元測試部分相對來講內容和價值相對小一點。
下圖是我的對手冊的簡單彙總(將圖片拖到瀏覽器新開頁面,以後放大能夠清晰不少),其中紅星表示重點,黃色表示次重點。此外,其中的集合處理、併發處理、MySQL規約和工程結構有必定理解難度,會專門放到重難點加強一節進行詳細分析。固然這只是我的的淺見,完整部分請見最下方的參考資料,目前阿里公司已推出這套規約的IDE插件,你們能夠試試。git

重難點加強

工程結構

Open Interface:提供RPC或Restful風格的接口,並經過框架進行網關安全控制、流量控制等。
 終端顯示層:前端模板渲染並執行顯示的層。
Web Layer: 主要是對訪問控制進行轉發, 各種基本參數校驗, 或者不復用的業務簡單處理等。
Service Layer:業務邏輯服務層。
Manager Layer:這一層比較有意思,既包含了常見的外部接口的Agent功能,也包含了對DAO接口的簡單封裝用於複用,還能夠在改爲構建對於DAO的緩存。
DAO Layer:與底層 MySQL、Hbase等進行數據交互,一般基於各種DAL框架。
ExternalInterface: 包括其它部門 RPC 開放接口, 基礎平臺, 其它公司的 HTTP 接口。
Tip: 實際項目中徹底能夠遵循該模式構建包的層次github

集合處理

集合操做一直是一個關鍵點,常見的小技巧包括經過Set元素惟一的特性,能夠快速對一個集合進行去重操做,JD8中經過steam流對集合操做作了不錯的加強。合理利用好集合的有序性 (sort) 和穩定性 (order) ,避免集合的無序性 (unsort) 和
不穩定性 (unorder) 帶來的負面影響,ArrayList是order&unsort;HashMap是unorder&unsort;TreeSet 是order&sort。
TIp: 不一樣類型Map集合K/V能不能存儲null值的狀況以下表所示sql

併發處理

合理的經過併發控制來高效利用系統資源是工程師永遠的追求,該手冊的很多要求很好的認識到本身在該方面的不足。
線程池的建立
過去一半都經過Executors 去建立線程池,實際上這是不合理的,好比FixedThreadPool的阻塞隊列大小Integer.MAX_VALUE,很容易形成大量請求的堆積,形成OOM。而ScheduledThreadPool容許線程的數量爲Integer.MAX_VALUE,更加容易出現OOM。所以必須使用ThreadPoolExecutor建立線程池,明確的制定線程池的參數。
使用鎖的原則
1.高併發時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,就不要用鎖 ; 能鎖區塊,就不要鎖整個方法體 ; 能用對象鎖,就不要用類鎖。
2.對多個資源、數據庫表、對象同時加鎖時,須要保持一致的加鎖順序,不然可能會形成死鎖。
3.併發修改同一記錄時,避免更新丟失,須要加鎖。要麼在應用層加鎖,要麼在緩存加鎖,要麼在數據庫層使用樂觀鎖,使用 version 做爲更新依據。若是每次訪問衝突機率小於 20%,推薦使用樂觀鎖,不然使用悲觀鎖。樂觀鎖的重試次數不得小於 3 次
CountDownLatch
使用 CountDownLatch 進行異步轉同步操做,每一個線程退出前必須調用 countDown方法,線程執行代碼注意 catch 異常,確保 countDown 方法被執行到,避免主線程沒法執行至 await 方法,直到超時才返回結果。須要注意子線程拋出異常堆棧,不能在主線程的try-catch塊中捕獲到。
ThreadLocalRandom
避免 Random 實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一seed 致使的性能降低,推薦使用ThreadLocalRandom。
Volatile
volatile 解決多線程內存不可見問題。對於一寫多讀,是能夠解決變量同步問題,可是若是多寫,一樣沒法解決線程安全問題。在完成飽漢的單例模式時,可使用Volatile關鍵字實現延遲初始化。
LongAdder
對於count++操做,可使用AtomicInteger count = new AtomicInteger();,JDK8中推薦使用LongAdder,經過減小樂觀鎖的重試次數提升性能。
HashMap
HashMap 在容量不夠進行 resize 時因爲高併發可能出現死鏈,致使 CPU 飆升,在開發過程當中可使用其它數據結構或加鎖來規避此風險。
ThreadLocal
ThreadLocal 對象建議使用 static修飾。這個變量是針對一個線程內全部操做共享的。數據庫

MYSQL規約

數據庫方面的優化一直困擾着我,書上的一下幾個原則給予我的在數據庫優化方面很多啓示。
索引長度
過去一直沒有注意過索引還有長度這個概念,如今才知道在varchar等類型字段上創建索引時,能夠指定索引長度,達到必定區分度便可,通常對於字符串類型數據,長度爲 20 的索引,區分度會高達 90%以上,可使用count(distinct left( 列名, 索引長度 )) / count( * )的區分度來肯定。編程

此外頁面搜索嚴禁左模糊或者全模糊,若是須要請走搜索引擎來解決。索引文件具備B-Tree的最左前綴匹配特性,若是左邊的值未肯定,那麼沒法使用此索引。
order by
在有order by的場景,請注意利用索引的有序性。例如where a =? and b =? order by c的索引爲a _ b _ c
覆蓋索引
利用覆蓋索引能夠減小原表查詢,經過索引頁(目錄)便可查到所需信息。一般來講,可以創建索引的種類包括主鍵索引、惟一索引、普通索引,而覆蓋索引是查詢的一種效果,能夠經過explain查看到extra 列會出現using index 。瀏覽器

分頁查詢
MySQL並非跳過offset行,而是取 offset + N 行,以後放棄offset行,返回所需N行,當數據量大時,推薦以下方式進行優化。先快速定位須要獲取的 id 段,而後再關聯:
SELECT a.* FROM 表 1 a, (select id from 表 1 where 條件 LIMIT 100000,20 ) b where a.id=b.id SQL 性能優化的目標
至少要達到 range 級別, 要求是 ref 級別, 若是能夠是 consts最好。
consts 單表中最多隻有一個匹配行(主鍵或者惟一索引),在優化階段便可讀取到數據。
ref 指的是使用普通的索引 (normal index) 。
range 對索引進行範圍檢索。
tip: type = index,索引物理文件全掃描,速度很是慢,這個 index 級別比較 range 還低,與全表掃描是小巫見大巫。緩存

在Mysql Workbench中表述稍微有些區別:consts沒變,Non-Unique Key Lookup表示ref, Index Range Scan表示range, full table Scan表示All, full index scan表示index,固然也能夠選擇Tabular視圖替代Visual視圖。安全

組合索引
區分度最高的在最左邊,對於where a =? and b =?來講,a 列的值越惟一越好。此外,存在非等號和等號混合判斷條件時, 在建索引時, 請把等號條件的列前置。
隱式轉換
防止因字段類型不一樣形成的隱式轉換,致使索引失效,當數據查詢超時,也須要把此做爲很重要的考慮部分。性能優化

參考資料

相關文章
相關標籤/搜索