我的以爲大多數狀況下跟着一篇優秀的博客配合着看就足夠了,以後再本身寫博客總結一遍加深印象,畫一下流程圖基本都能理順。(圖爲學AQS時本人畫的獲取獨佔鎖流程圖)git
配合idea看類之間的關係(ctrl+alt+shift+u)的功能也能更好的理解整個項目的總體架構。由於不少源碼其實並非真的複雜,只是爲了擴展性優雅簡潔等緣由創建了大量的接口和抽象類以及各類設計模式,使得項目看起來很龐大很複雜,藉助這個功能有利於你排除掉一些你暫時不想去關心的設計邏輯。知道那個部分纔是最核心的邏輯,專一於去看核心代碼。github
可是若是你看的博客裏面恰好缺乏了一部分你想看的內容,而你又找不到資料,須要本身去看,又或者你想看的源碼一點點資料都找不到的狀況下想去看源碼。面試
這個時候比較有做用的就是註釋,源碼中的註釋看不懂也不要緊,放到百度翻譯裏基本也能理解大概的意思。仔細看完方法或類的註釋以後你就理解了接下來這個類大體是在作什麼,以後讀它的源碼會通順不少,有一些方法或類甚至在你看完註釋以後就已經能知道你想看的內容了,已經沒有須要繼續往下讀了。算法
不只僅是類或方法的註釋文檔,方法中代碼的註釋也很重要,基本上稍微複雜一點點的代碼,甚至有時候加個鎖,做者都會認認真真的寫一行註釋解釋本身這麼作的緣由。spring
還有一點是適當忽略一些不重要的細節,這個主要看你想看什麼,通常咱們看第一遍大多數只是想知道大體的流程是什麼樣的,因此能夠適當忽略併發邏輯和一些方法裏的內容(看一眼註釋先知道這個方法會作什麼的就夠了)。第一遍大體知道流程,第二第三遍再去深究細節和併發邏輯等。mongodb
多用debug,不少時候源碼走的路線會和你想象中的有很大不一樣,你覺得會進入這個if,其實他偷偷進了else。設計模式
常常看到利用短路機制的代碼,這裏以 AbstractQueuedSynchronizer 的 acquire 方法爲例子,只有 tryAcquire 獲取鎖失敗, !tryAcquire 返回 true 時纔會執行後面進入阻塞隊列並掛起的方法,若是獲取鎖成功了,根據短路機制天然不會執行入隊方法。mybatis
// AbstractQueuedSynchronizer.acquire(int arg)
if (!tryAcquire(arg) &&架構
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) { selfInterrupt();
}併發
ReentrantReadWriteLock的這段代碼裏將AQS的state一分爲二給共享鎖和獨佔鎖使用,我的以爲這種設計很是巧妙:
// ReentrantReadWriteLock
abstract static class Sync extends AbstractQueuedSynchronizer {
// 下面這塊說的就是將 state 一分爲二,高 16 位用於共享模式,低16位用於獨佔模式 static final int SHARED\_SHIFT = 16; static final int SHARED\_UNIT = (1 << SHARED\_SHIFT); static final int MAX\_COUNT = (1 << SHARED\_SHIFT) - 1; static final int EXCLUSIVE\_MASK = (1 << SHARED\_SHIFT) - 1; // 取 c 的高 16 位值,表明讀鎖的獲取次數(包括重入) static int sharedCount(int c) { return c >>> SHARED\_SHIFT; } // 取 c 的低 16 位值,表明寫鎖的重入次數,由於寫鎖是獨佔模式 static int exclusiveCount(int c) { return c & EXCLUSIVE\_MASK; }
忘記在哪裏看到的了,翻了一下瀏覽記錄應該是在Java AIO部分的源碼裏,這種寫法感受很簡潔就記下來了,不過可讀性彷佛不過高,特別是第一種乍一看還覺得是lambda表達式
意思等同於 for (int i = 0; i < n; i++) ,可是 while(n-- > 0) 和 while (--n >= 0) 這種寫法會直接改變n的值
在不少jdk的源碼中咱們均可以看到 xx = null // help GC 這樣的代碼,用來置空引用,幫助jvm完成gc。具體能夠了解可達性算法。
這裏咱們以LinkList爲例子:
// LinkList 的方法
private E unlinkFirst(Node<E> f) {
final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element;
}
在不少地方都會使用位移來進行運算,平時寫算法題也同樣不少人都這麼使用,下面以 ArrayList 的 grow 方法爲例子,這裏經過右移1位使 oldCapacity 變爲原來的0.5倍,以後加上它自己獲得 newCapacity
// ArrayList.grow(int minCapacity)
private void grow(int minCapacity) {
// . . . . . . int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity就是1.5倍的oldCapacity // . . . . . .
}
而源碼帶給你的可不只僅只是這一些,更多的是編碼習慣以及這一個技術最底層的運行原理,當出現問題或者須要這個技術的輔助的時候,你能夠更好理解這一技術能起到的做用,以及會產生的問題,雙方均衡下,在作出決定,這也是爲何如今市面上面試考察源碼的東西愈來愈多的緣由。總結就是如下幾點
只要是代碼,就會有bug,只是說bug的多與少、深與淺罷了。如今你們都喜歡發佈、使用開源項目,不一樣的開源項目社區成熟度、代碼質量又會有較大的差別,遇到bug就不足爲奇了。
固然,遇到bug確定是先在網上搜索是否有相似的問題,通常能夠在google、Stack Overflow、項目的issues裏面有對應的關鍵詞搜索。若是搜不到,那麼就只能看源碼解決了
若是咱們須要將一個開源項目用到本身的項目中,那麼就必須瞭解這項項目的優缺點,並深知原理,對部分細節(尤爲是項目的優點、feature)進行深刻研究。
若是是成熟的開源項目,遇到問題也許能google到不少答案;但若是是一個處於快速發展中的開源項目,多瞭解其架構、核心原理,也能幫助快速定位問題。
另外,有的項目文檔可能不那麼豐富,但又不得不使用,那麼如何以正確的姿式使用呢?也得參考源碼
看源碼也是一種不錯的學習方式(雖然不必定不是最佳的方式),尤爲對於比較優秀的開源項目,能讓人大開眼界。
即便是出於學習的目的,也是有不少側重的,好比
學習語言:代碼風格、規範、慣用法、高級語法。對於某個語言的新手,找一個熟悉領域的開源項目來深刻掌握這門語言,也是一個不錯的注意。
學習設計:數據接口、框架、總體架構
學習理論:算法、協議。好比我以前寫過的[raft協議][raft],光看論文是很枯燥的,並且算法理論到工程實踐仍是有必定的差距,這個時候結合開源項目([mongodb][])實現每每更事半功倍。
通常來講,咱們剛開始僅僅是使用一個開源項目,但隨着使用的深刻,會發現一些本身須要的功能並無很好的支持,向項目組提的issues也可能得不到快速的響應,這個時候就要本身開分支,改代碼,加功能了。
固然,比較好的是將本身分支比較好的新feature 給原項目提merge request,反哺開源項目,好比阿里的[Blink],而這也是將來在你面試過程當中濃墨重彩的一筆
他山之石能夠攻玉,若是有須要從新開始本身造輪子,那麼參考一些已有的、優秀的輪子確定是有好處的。
固然了,整這麼多最後仍是爲了一份更好的工做,那如今市面上考察的源碼知識點都有哪些呢?
如今市場考察最多的源碼主要有如下幾點:jdk、spring、mybatis、dubbo、springMVC、Netty
後期會將文件上傳git:https://github.com/biws-byte/pdf
前期還請你們移步,關注公衆號:Java架構師聯盟,後臺回覆源碼查看獲取方式