首先是我的的一些閱讀源碼的小技巧,不必定適用每一個人,能夠直接跳過。算法
我的以爲大多數狀況下跟着一篇優秀的博客配合着看就足夠了,以後再本身寫博客總結一遍加深印象,畫一下流程圖基本都能理順。(圖爲學AQS時本人畫的獲取獨佔鎖流程圖)設計模式
配合idea看類之間的關係(ctrl+alt+shift+u)的功能也能更好的理解整個項目的總體架構。由於不少源碼其實並非真的複雜,只是爲了擴展性優雅簡潔等緣由創建了大量的接口和抽象類以及各類設計模式,使得項目看起來很龐大很複雜,藉助這個功能有利於你排除掉一些你暫時不想去關心的設計邏輯。知道那個部分纔是最核心的邏輯,專一於去看核心代碼。 架構
可是若是你看的博客裏面恰好缺乏了一部分你想看的內容,而你又找不到資料,須要本身去看,又或者你想看的源碼一點點資料都找不到的狀況下想去看源碼。併發
這個時候比較有做用的就是註釋,源碼中的註釋看不懂也不要緊,放到百度翻譯裏基本也能理解大概的意思。仔細看完方法或類的註釋以後你就理解了接下來這個類大體是在作什麼,以後讀它的源碼會通順不少,有一些方法或類甚至在你看完註釋以後就已經能知道你想看的內容了,已經沒有須要繼續往下讀了。jvm
不只僅是類或方法的註釋文檔,方法中代碼的註釋也很重要,基本上稍微複雜一點點的代碼,甚至有時候加個鎖,做者都會認認真真的寫一行註釋解釋本身這麼作的緣由。ide
還有一點是適當忽略一些不重要的細節,這個主要看你想看什麼,通常咱們看第一遍大多數只是想知道大體的流程是什麼樣的,因此能夠適當忽略併發邏輯和一些方法裏的內容(看一眼註釋先知道這個方法會作什麼的就夠了)。第一遍大體知道流程,第二第三遍再去深究細節和併發邏輯等。ui
多用debug,不少時候源碼走的路線會和你想象中的有很大不一樣,你覺得會進入這個if,其實他偷偷進了else。idea
常常看到利用短路機制的代碼,這裏以 AbstractQueuedSynchronizer 的 acquire 方法爲例子,只有 tryAcquire 獲取鎖失敗, !tryAcquire 返回 true 時纔會執行後面進入阻塞隊列並掛起的方法,若是獲取鎖成功了,根據短路機制天然不會執行入隊方法。spa
// 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 // . . . . . . }
以上是我目前的水平所能總結出來的,後續學到其餘的會繼續更新,若是你們有什麼補充的請告訴我
最後慣例附一圖:(根本不存在想僱傭個人地方( ´_ゝ`).jpg)