不知不覺樹義已經工作 5 年了,一路走來磕磕碰碰但總算有了自己的一點小體會。對於一個 Java 開發人員來說,到了 5 年的關鍵節點,需要掌握哪些知識點呢?經過我自己的總結,我列出了下面的思維導圖。

從上面的圖片我們可以看出大致分為三個部分:JDK 源碼、JVM 原理、框架源碼。
JDK源碼
JDK 源碼是一切的基礎,許多框架都參考了 JDK 源碼的實現思路,因此弄懂 JDK 源碼是一件非常重要的事情。而 JDK 源碼又可以分為下面 4 大塊:
- 集合源碼
- 並發集合源碼
- 並發包源碼
- 阻塞隊列源碼
- 線程池源碼
集合源碼
說到集合,我們大家都非常熟悉,這可是我們工作中用得非常多的一類 API。但會用了,還得知道它到底是如何實現的,這樣才可以避免踩坑。JDK 源碼中的集合並不是特別多,大概有 四大類大概 14 個常用的 API。
List集合
- ArrayList:列表集合經典實現。
- Vector:列表集合經典實現,線程安全,與 ArrayList 對應。
- LinkedList:鏈表結構的經典實現。
- Stack:棧結構的經典實現,先進后出的數據結構。繼承了 Vector,線程安全。
Set集合
- HashSet:Set 集合的哈希實現。
- LinkedHashSet:Set 集合的哈希實現,維護了元素插入順序。
- TreeSet:Set 集合的有序實現。
Queue集合
- PriorityQueue:優先級隊列
- LinkedList:雙向隊列實現
- ArrayDeque:雙向循環隊列實現
Map集合
- HashMap:Map 集合的經典哈希實現。
- LinkedHashMap:在 HashMap 的基礎上,增加了對插入元素的鏈表維護。
- WeakedHashMap:在 HashMap 的基礎上,使強引用變為弱引用。
- TreeMap:Map 集合的有序實現。底層是紅黑樹的經典實現。
在這 14 個常用的 API 中雖然有一些我們還沒使用過,但如果你要建立起一套完整的知識體系,那么還是有必要去仔細琢磨一下它們的作用,並且對它們進行橫向比較的。
並發集合源碼
我們前面說到的集合源碼,它們大部分都是線程不安全的,它們在多線程的環境下使用會產生各種各樣的問題。而線程安全與並發安全又不一樣,線程安全考慮的是絕對的安全,而並發安全則是犧牲部分特性來提高並發效率。也就是說並發集合適合在多線程環境下使用,並且效率足夠高,能夠應對高並發的情況。
在 JDK 的並發集合源碼中,一共有 7 個常用的並發集合。
- ConcurrentHashMap:高並發的HashMap
- ConcurrentSkipListMap:高並發下的TreeMap(基於跳表實現)
- ConcurrentSkipListSet:內部使用ConcurrentSkipListMap實現
- CopyOnWriteArrayList:高並發的ArrayList,適合讀場景。
- CopyOnWriteArraySet:高並發的Set集合,使用CopyOnWriteArrayList實現。
- ConcurrentLinkedQueue:高並發的鏈表隊列。
- ConcurrentLinkedDeque:高並發的雙向鏈表隊列。
雖然有 7 個並發集合,但是實際上只有 5 個左右,因為另外兩個都直接用代理的方式委托實現。例如:CopyOnWriteArraySet 類內部並沒有具體的邏輯實現,而是直接委托 CopyOnWriteArrayList 實現。
並發包源碼
我們前面說過許多集合都是線程不安全的,在多線程環境、甚至高並發環境需要使用並發集合。那么並發集合到底是怎么實現線程安全的呢?在 JDK1.8 之后,並發集合大部分都使用 CAS 來實現線程安全。而其實在 JDK1.8 之前,許多線程安全都是使用鎖來實現的。而說到鎖,我們就必須了解一下並發包源碼。
並發包源碼從零開始定義了一整套實現並發安全的機制,並且還提供了不少方便使用的並發工具。我們通過並發包就可以非常方便地實現多線程下的線程安全和並發控制,后面說到的阻塞隊列都是以這個為基礎的。
並發包是一整套接口和實現的定義,其主要的類和實現如下:

在並發源碼最頂層的是 AbstractQueueSynchronizer 接口,其定義了並發控制最為基礎的幾個接口,之后的 Lock、ReentrantLock、ReentrantReadWriteLock 都是在這基礎上實現的。而 Condition 接口則是繼 AbstractQueueSynchronizer 接口之后的另一個重要接口,其定義了分支條件,使得並發適用於更復雜的業務。
定義好了 AbstractQueueSynchronizer 和 Condition 接口,並發包的基礎就搭建好了。並發包中提供了 CountDownLatch、CyclicBarrier 等並發工具類來實現常用的並發操作,這些工具類都是使用前面提到的 Lock 來實現的。
阻塞隊列源碼
阻塞隊列其實是屬於並發包的一部分,但因為其功能性特別明顯,所以我們專門挑出來單獨說。阻塞隊列用於在高並發環境下進行數據的交換,其實現基礎是我們前面說到的並發包,沒有並發包就沒有阻塞隊列。
在 JDK 中,阻塞隊列一共可以分為三大類一共 8 個常用的阻塞隊列。
基礎實現
這塊是阻塞隊列最基礎的實現
- ArrayBlockingQueue:數組組成的有界阻塞隊列
- LinkedBlockingQueue:鏈表組成的無界阻塞隊列
- LinkedBlockingDeque:鏈表組成的雙向阻塞隊列
有序延遲實現
這塊的阻塞隊列還實現了元素的排序以及延遲功能,只有時間到了才能出隊列。
- PriorityBlockingQueue:支持優先級排序的無界阻塞隊列
- DelayQueue:支持優先級實現的無界延遲阻塞隊列
- DelayedWorkQueue:線程池中的延遲阻塞隊列
數據交換實現
這塊阻塞隊列主要用於多線程之間的數據交換
- SynchronousQueue:不存儲元素的數據交換阻塞隊列
- LinkedTransferQueue:鏈表組成的數據交換無界阻塞隊列

線程池源碼
線程池也是 JDK 源碼中非常重要的一塊,妥善利用線程池可以提高效率。而線程池的基礎其實就是我們前面講到的阻塞隊列,線程池的延遲功能都是使用阻塞隊列實現的。線程池的整體架構比較多,但是並不復雜,也沒有什么難點。如果弄懂了線程池的整體類結構,那么線程池也就沒什么太大的問題了。

JVM原理
JVM 可以說是 Java 程序員必須要掌握的基礎知識了。初學者或許會搞不懂這些東西到底有什么用,一開始學習都是為了面試用。但老司機告訴你學習 JVM 原理有下面兩個非常重要的用處:
- 理解 Java 語言特性。Java 代碼寫出來的只是語言層面的東西,當我們要了解一個特性是如何實現的,我們就需要深入到字節碼層面。例如:boolean 這個類型,在 Java 語言層面是存在的。但是其在字節碼層面是不存在的,其在字節碼層面是使用 Integer 的 1 和 0 表示 true 和 false。
- 學習排查線上問題。我們遇到線上 JVM 問題,經常提示說:
OutOfMemoryError: Java heap space。這時候你會不知道從何入手,這是因為你不懂 JVM 的內存結構。所以你必須去學習 JVM 的內存結構,如何排查問題發生在哪塊內存,如何解決問題。而這一切的基礎就是 JVM 的基礎知識。
關於 JVM 的基礎知識,我寫了一個系列的文章來介紹,有興趣的可以閱讀以下:JVM系列文章
框架源碼
學習完 JDK 的源碼,我們就需要把我們常用的框架源碼都弄清楚。這樣在遇到框架問題的時候,我們才可以快速地排查問題。

上面的思維導圖從上到下都是逐次遞進的。我們學習了 JDK 源碼,再學習 Web 框架就可以實現簡單的 Web 項目。而隨着業務增長,我們需要加入 RPC 服務化框架將其服務化。而隨着業務復雜化和井噴,我們需要加入消息隊列和緩存來進一步提高業務的穩定性。
Web框架
Spring 和 MyBatis 可以說是 Java Web 開發者必學的兩個框架了,因此對這兩個框架有必要做一個深入的了解。
對於 Spring 來說,其整個源碼體系太過於復雜,所以我們還是得抓住重點。對於 Spring 來說,最重要的是其 AOP 和 IoC 的實現,以及其容器體系和常用的接口。而對於 MyBatis 來說,其體系相對沒有 Spring 那么復雜,所以可以稍微深入一些。
RPC框架
在所有 RPC 框架中,dubbo 可以說是最通用的一個了。所以如果你所在的公司沒有自研的 RPC 框架,那么你不妨可以將 dubbo 作為你的學習框架。
對於 RPC 框架來說,其實無非就是封裝對象代理,最后通過與服務提供者進行網絡通信。但是如何進行封裝,如果進行負載均衡的實現,這就考驗一個框架設計者的功力了。
一致性框架
對於分布式系統,非常重要的一個組件就是一致性框架。在這些框架中,最常見的兩個是 Zookeeper 和 Eureka。Zookeeper 實現了 CAP 中的 CP(即注重強一致性),而 Eureka 則是實現了 CAP 中的 AP(即注重可用性)。
雖然平常我們都將 Zookeeper 和 Eureka 作為服務化的協調組件,基本上沒有什么機會深入學習。但是有機會還是可以深入了解一下的。
消息隊列
消息隊列可以說是實現業務解耦以及突發流量的利器。而在大型業務場景中,最常用的就是 Kafka 和 RocketMQ 了,因此弄懂這兩個消息隊列的原理基本上就足夠用了。
對於消息隊列,建議先選擇一個深入研究,先弄懂其基本原理,之后再閱讀源碼驗證想法。因為 RocketMQ 是基於 Kafka 改進的,所以建議先從 Kafka 入手研究。Kafka 研究得差不多了,RocketMQ 的研究也會進展飛速。
緩存框架
緩存框架可以說是高並發下必用的一個框架了,但我們經常只是使用它,而不知道起內部的原理和構造。因此找個時間深入學習下原理,還是很有必要的。
網絡框架
對於一些網絡項目,例如聊天 IM 等,就需要用到 Netty 等框架。而 Netty 又是這類網絡框架的佼佼者,通過對其源碼的研究,可以學到不少知識。
搜索框架
對於一些搜索功能的項目,單純的數據庫 SQL 查詢已經無法滿足需求了,這時候 ElasticSearch 的學習和研究就提上議程了。有時間的話,研究學習一下還是很有必要的。
增量訂閱框架
Canal 和 Otter 框架可以幫助你獲得數據庫的變化信息,從而更方便地做業務擴展。對於這類框架,屬於特定領域的細分框架,有時間可以研究一下。
總結
作為一個工作了 5 年的開發,上面的知識體系還是未能完全消化,只能說是對於部分有些掌握。如果你也想構建自己的知識體系,那么我建議你可以按照我列出的順序去學習。先研究學習 JDK 源碼,之后學習 JVM 原理,最后再去研究學習框架源碼。而框架源碼的研究也從該框架的常用程度排序,對於 ElasticSearch 這類不常用的,可以放在后面。而對於 Spring 這些用得很多的,則需要放在前面。
今天也只是簡略地提了一下整個知識體系,后續有空閑時間會繼續慢慢分享相關文章。有興趣的朋友不妨關注一下我,這樣能及時查看后續文章。
