1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官問我平時(shí)怎么看源碼的,我把這篇文章甩給他了。

        共 7366字,需瀏覽 15分鐘

         ·

        2020-12-16 21:52

        本文來自作者投稿,原作者:WwpwW

        1.1,為什么要分析源碼?

        分析源碼可以培養(yǎng)一下自己獨(dú)立思考問題的能力(愿意讀源碼找問題的能力),最重要的是我們不用再買紙質(zhì)書去學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)了,數(shù)據(jù)結(jié)構(gòu)的應(yīng)用都在源碼里面了,正如那句被人熟知的"營養(yǎng)都在湯里面"一樣,當(dāng)我們看過一遍一遍數(shù)據(jù)結(jié)構(gòu)的理論知識后還是想不起它在哪里用到時(shí),可能看一看源碼加上自己的一點(diǎn)思考時(shí)就知道它的使用場景了,解答完畢。

        1.2,分析源碼的好處是?

        其實(shí),對于工作一段時(shí)間的小伙伴來說,我們都是面向業(yè)務(wù)開發(fā),就是被人飯后談資的增刪改查程序員/程序猿,當(dāng)然了,有的人說起來這樣的話,"api調(diào)包俠"就有點(diǎn)過分了,其實(shí)對于我個(gè)人來說,我是受不了這樣的話語的,因?yàn)樵鰟h改查是常用的操作,即滿足了"二八原則",其實(shí),程序員/程序猿都是工作中不可或缺的一部分,也是企業(yè)開發(fā)應(yīng)用中重要的一環(huán),分析源碼可能就會帶來顯而易見的內(nèi)功提升,其次就是分析源碼的過程中就是在向優(yōu)秀的人學(xué)習(xí)的一種體現(xiàn),畢竟源碼里面隱藏了大師多年的心得和思想。

        1.3,如何分析源碼?

        在整個(gè)文章的閱讀過程中,想必你已經(jīng)學(xué)會了如何分析源碼了,從哪入手,這也是一種潛移默化的過程。

        本文以分析LinkedBlockingQueue的源碼為例,介紹下應(yīng)該如何看源碼!

        二, ?方法分析

        2.1,構(gòu)造函數(shù)

        public?LinkedBlockingQueue()?{
        ?//創(chuàng)建容量為整形最大值
        ????this(Integer.MAX_VALUE);
        }

        public?LinkedBlockingQueue(int?capacity)?{
        ????//若capacity小于0,則直接拋出參數(shù)不合法的異常
        ????if?(capacity?<=?0)?throw?new?IllegalArgumentException();
        ????this.capacity?=?capacity;
        ????//默認(rèn)創(chuàng)建一個(gè)元素為null的節(jié)點(diǎn)Node
        ????last?=?head?=?new?Node(null);
        }

        2.2,add()方法

        public?boolean?add(E?e)?{
        ????//添加到隊(duì)列的末尾
        ????????addLast(e);
        ????????return?true;
        ????}
        //第二步
        public?void?addLast(E?e)?{
        ????//若添加失敗,則直接拋出隊(duì)列已滿的異常信息,給與提示
        ????????if?(!offerLast(e))
        ????????????throw?new?IllegalStateException("Deque?full");
        ????}
        //第三步
        public?boolean?offerLast(E?e)?{
        ????//若添加的元素e為null,則直接拋出空指針異常,因?yàn)椴辉试S添加元素為null的情況
        ????????if?(e?==?null)?throw?new?NullPointerException();
        ????//構(gòu)造一個(gè)元素為e的節(jié)點(diǎn)node
        ????????Node?node?=?new?Node(e);
        ????????final?ReentrantLock?lock?=?this.lock;
        ????//進(jìn)行加鎖操作
        ????????lock.lock();
        ????????try?{
        ????????????//進(jìn)行第四步操作
        ????????????return?linkLast(node);
        ????????}?finally?{
        ?????//進(jìn)行釋放鎖,當(dāng)然了,這里你要記住鎖釋放是放到finally語句塊里面的(重要)
        ????????????lock.unlock();
        ????????}
        ????}
        //第四步
        private?boolean?linkLast(Node?node)?{
        ????????//?assert?lock.isHeldByCurrentThread();
        ????//如果隊(duì)列里元素個(gè)數(shù)大于等于了隊(duì)列的容量,說明此時(shí)不能再將元素放入隊(duì)列里面了,直接返回false即可
        ????????if?(count?>=?capacity)
        ????????????return?false;
        ????//創(chuàng)建一個(gè)臨時(shí)變量l,將最后一個(gè)節(jié)點(diǎn)的引用賦值給l
        ????????Node?l?=?last;
        ????//將最后一個(gè)節(jié)點(diǎn)的引用賦值給新節(jié)點(diǎn)node的前一個(gè)引用(鏈表的特點(diǎn))
        ????????node.prev?=?l;
        ????//將新節(jié)點(diǎn)node賦值給最后一個(gè)節(jié)點(diǎn)(因?yàn)樵厝珀?duì)列是放在隊(duì)列的末尾的,隊(duì)列的特點(diǎn)->先進(jìn)先出)
        ????????last?=?node;
        ????//為什么這里要判斷first是否為null呢?因?yàn)樘砑訒r(shí)不知道隊(duì)列里是否已經(jīng)存在元素,若first為null,說明隊(duì)列里沒有元素
        ????????if?(first?==?null)
        ????//此時(shí)的node就是第一個(gè)結(jié)點(diǎn),賦值即可
        ????????????first?=?node;
        ????????else
        ????//將新節(jié)點(diǎn)node掛在原有結(jié)點(diǎn)的下一個(gè),即l.next=node
        ????????????l.next?=?node;
        ????//隊(duì)列元素個(gè)數(shù)進(jìn)行加一
        ????????++count;
        ????//發(fā)送一個(gè)信號,隊(duì)列不滿的信號
        ????????notEmpty.signal();
        ????//默認(rèn)將元素e添加到隊(duì)列里面了~,即返回true
        ????????return?true;
        ????}

        2.3,size()方法

        ?public?int?size()?{
        ?????//直接返回隊(duì)列里表示元素個(gè)數(shù)的成員變量count即可
        ????????return?count.get();
        ????}

        2.4,peek()方法

        public?E?peek()?{
        ????//若隊(duì)列元素個(gè)數(shù)為0,說明隊(duì)列里還未有元素,直接返回null
        ????????if?(count.get()?==?0)
        ????????????return?null;
        ????//獲取鎖
        ????????final?ReentrantLock?takeLock?=?this.takeLock;
        ????//進(jìn)行加鎖操作
        ????????takeLock.lock();
        ????????try?{
        ????//獲取隊(duì)列的第一個(gè)結(jié)點(diǎn)引用first
        ????????????Node?first?=?head.next;
        ????//若隊(duì)列的第一個(gè)節(jié)點(diǎn)引用為null,則直接返回null即可
        ????????????if?(first?==?null)
        ????????????????return?null;
        ????????????else
        ?????//獲取第一個(gè)節(jié)點(diǎn)引用first的元素item返回
        ????????????????return?first.item;
        ????????}?finally?{
        ????//進(jìn)行釋放鎖,記得釋放鎖要放在finally語句塊里,確保鎖可以得到釋放
        ????????????takeLock.unlock();
        ????????}
        ????}

        2.5,contains()方法

        public?boolean?contains(Object?o)?{
        ????//引入隊(duì)列里不允許放入null,所以若元素o為null,則直接返回false,相當(dāng)于進(jìn)行了前置校驗(yàn)操作
        ????????if?(o?==?null)?return?false;
        ????//第二步
        ????????fullyLock();
        ????????try?{
        ????//循環(huán)遍歷隊(duì)列的每個(gè)節(jié)點(diǎn)node的元素item是否與元素o相等,若存在相等元素,則包含,返回true即可
        ????????????for?(Node?p?=?head.next;?p?!=?null;?p?=?p.next)
        ????????????????if?(o.equals(p.item))
        ????????????????????return?true;
        ????????????return?false;
        ????????}?finally?{
        ?????//第四步,第三次說明了,釋放鎖要放在finally語句塊里面,確保鎖可以得到正確的釋放
        ????????????fullyUnlock();
        ????????}
        ????}
        ????/**
        ?????*?Locks?to?prevent?both?puts?and?takes.
        ?????*/
        ???//第二步,上面的注釋說明,進(jìn)行加鎖操作,禁止進(jìn)行添加元素到隊(duì)列,禁止進(jìn)行從隊(duì)列里取元素,下面就慢慢分析take()方法了
        ????void?fullyLock()?{
        ????????putLock.lock();
        ????????takeLock.lock();
        ????}
        ???//第四步,因?yàn)榧渔i和釋放鎖是成對的,所以最后一定要記得釋放鎖哈~,即加了什么鎖,要對應(yīng)的解鎖
        ???/**
        ?????*?Unlocks?to?allow?both?puts?and?takes.
        ?????*/
        ????void?fullyUnlock()?{
        ????????takeLock.unlock();
        ????????putLock.unlock();
        ????}

        2.6,put()方法

        public?void?put(E?e)?throws?InterruptedException?{
        ????//這個(gè)隊(duì)列是不允許添加空元素的,先來個(gè)前置校驗(yàn),元素為null,則拋出NPE異常
        ????????if?(e?==?null)?throw?new?NullPointerException();
        ????????//?Note:?convention?in?all?put/take/etc?is?to?preset?local?var
        ????????//?holding?count?negative?to?indicate?failure?unless?set.
        ????????int?c?=?-1;
        ????//構(gòu)造一個(gè)節(jié)點(diǎn)node,元素為e
        ????????Node?node?=?new?Node(e);
        ????//獲取putLock這把鎖引用
        ????????final?ReentrantLock?putLock?=?this.putLock;
        ????????final?AtomicInteger?count?=?this.count;
        ????????putLock.lockInterruptibly();
        ????????try?{
        ?????//當(dāng)隊(duì)列元素個(gè)數(shù)等于隊(duì)列容量capacity時(shí),進(jìn)行等待,這里存在一個(gè)阻塞操作
        ????????????while?(count.get()?==?capacity)?{
        ????????????????notFull.await();
        ????????????}
        ??????//第二步操作,入隊(duì)列
        ????????????enqueue(node);
        ??????//元素個(gè)數(shù)增加1,這里使用的是cas機(jī)制
        ????????????c?=?count.getAndIncrement();
        ????????????if?(c?+?1???????//進(jìn)行信號的通知,和notify一樣
        ????????????????notFull.signal();
        ????????}?finally?{
        ??????//釋放鎖操作
        ????????????putLock.unlock();
        ????????}
        ????????if?(c?==?0)
        ????????????signalNotEmpty();
        ????}
        ???//第二步,入隊(duì)列操作(隊(duì)列的特點(diǎn)是先進(jìn)先出)
        ????private?void?enqueue(Node?node)?{
        ????????//將新元素結(jié)點(diǎn)node掛在原有隊(duì)列最后一個(gè)元素的后面,然后將最后一個(gè)節(jié)點(diǎn)的引用賦值給last
        ????????last?=?last.next?=?node;
        ????}

        2.7,take()方法

        public?E?take()?throws?InterruptedException?{
        ????????E?x;
        ????????int?c?=?-1;
        ????????final?AtomicInteger?count?=?this.count;
        ?????//獲取takeLock鎖引用
        ????????final?ReentrantLock?takeLock?=?this.takeLock;
        ?????//這把鎖是可以中斷的
        ????????takeLock.lockInterruptibly();
        ????????try?{
        ?????//若隊(duì)列元素個(gè)數(shù)為0,說明隊(duì)列里沒元素了,此時(shí)需要進(jìn)行發(fā)送一個(gè)等待的通知
        ????????????while?(count.get()?==?0)?{
        ????????????????notEmpty.await();
        ????????????}
        ?????//進(jìn)行從隊(duì)列里進(jìn)行取元素操作,見下面的第二步操作?
        ????????????x?=?dequeue();
        ?????//隊(duì)列元素個(gè)數(shù)進(jìn)行減一操作
        ????????????c?=?count.getAndDecrement();
        ????????????if?(c?>?1)
        ????????????????notEmpty.signal();
        ????????}?finally?{
        ??????//?釋放鎖
        ????????????takeLock.unlock();
        ????????}
        ????????if?(c?==?capacity)
        ????????????signalNotFull();
        ????????return?x;
        ????}
        ???//第二步操作
        ????private?E?dequeue()?{
        ???//下面的操作就是隊(duì)首元素出來了,隊(duì)列的后面元素要前移,如果這一步不是很好理解的話,可以按照下面的方式進(jìn)行debug看下
        ???//在分析這塊時(shí),自己也有所成長,因?yàn)閐ebug是可以看到元素在數(shù)據(jù)流中如何處理的
        ????????Node?h?=?head;
        ????????Node?first?=?h.next;
        ????????h.next?=?h;?//?help?GC
        ????????head?=?first;
        ???//獲取隊(duì)首元素x
        ????????E?x?=?first.item;
        ????//觸發(fā)gc機(jī)制進(jìn)行垃圾回收,什么是垃圾對象呢,就是不可達(dá)對象,不了解的可以看下jvm對應(yīng)的機(jī)制
        ????????first.item?=?null;
        ????//返回隊(duì)列的隊(duì)首元素
        ????????return?x;
        ????}
        image-20201122102406286

        2.8,remove()方法

        ?public?boolean?remove(Object?o)?{
        ?????//這個(gè)隊(duì)列里不允許添加元素為null的元素,所以這里在刪除的時(shí)候做了一下前置校驗(yàn)
        ????????if?(o?==?null)?return?false;
        ?????//第二步,禁止入隊(duì)列和出隊(duì)列操作,和上文的contains()方法采取的策略一致
        ????????fullyLock();
        ????????try?{
        ??????//循環(huán)遍歷隊(duì)列的每個(gè)元素,進(jìn)行比較,這里是不是和你寫業(yè)務(wù)邏輯方法一樣,嘖嘖,有點(diǎn)意思吧
        ??????//這里你就明白為什么要看源碼了,以及看源碼你能得到什么
        ????????????for?(Node?trail?=?head,?p?=?trail.next;
        ?????????????????p?!=?null;
        ?????????????????trail?=?p,?p?=?p.next)?{
        ???????//此時(shí)找到待刪除的元素o
        ????????????????if?(o.equals(p.item))?{
        ???????//進(jìn)行第三步操作
        ????????????????????unlink(p,?trail);
        ????????????????????return?true;
        ????????????????}
        ????????????}
        ????????????return?false;
        ????????}?finally?{
        ????????????fullyUnlock();
        ????????}
        ????}
        //第二步,禁止入隊(duì)列,出隊(duì)列操作
        ?void?fullyLock()?{
        ????????putLock.lock();
        ????????takeLock.lock();
        ????}
        //第三步
        void?unlink(Node?p,?Node?trail)?{
        ???//觸發(fā)gc機(jī)制,將垃圾對象進(jìn)行回收
        ????????p.item?=?null;
        ????//將待刪除元素的下一個(gè)節(jié)點(diǎn)【掛載】待刪除元素的前一個(gè)元素的next后面
        ????????trail.next?=?p.next;
        ????//判斷待刪除的元素是否是隊(duì)列的最后一個(gè)元素,如果是,則trail賦值給last,這里你可以想象一下鏈表的刪除操作
        ????????if?(last?==?p)
        ????????????last?=?trail;
        ????//隊(duì)列的元素個(gè)數(shù)減一
        ????????if?(count.getAndDecrement()?==?capacity)
        ????????????notFull.signal();
        ????}

        2.9,clear()方法

        ????/**
        ?????*?Atomically?removes?all?of?the?elements?from?this?queue.
        ?????*?The?queue?will?be?empty?after?this?call?returns.
        ?????*/
        ????public?void?clear()?{
        ????????//方法上的注釋已經(jīng)說明了clear()方法的作用是干什么的了,很清晰
        ????????//在clear()操作時(shí),不允許進(jìn)行put/take操作,進(jìn)行了加鎖
        ????????fullyLock();
        ????????try?{
        ????????//循環(huán)遍歷隊(duì)列的每一個(gè)元素,將其節(jié)點(diǎn)node對應(yīng)的元素item置為null,觸發(fā)gc
        ????????????for?(Node?p,?h?=?head;?(p?=?h.next)?!=?null;?h?=?p)?{
        ????????????????h.next?=?h;
        ????????????????p.item?=?null;
        ????????????}
        ????????//隊(duì)首隊(duì)尾相同表明隊(duì)列為空了
        ????????????head?=?last;
        ???????//將隊(duì)列的容量capacity置為0
        ????????????if?(count.getAndSet(0)?==?capacity)
        ????????????????notFull.signal();
        ????????}?finally?{
        ???????//記得在這里釋放鎖
        ????????????fullyUnlock();
        ????????}
        ????}

        2.10, toArray()方法

        ?public?Object[]?toArray()?{
        ?????//禁止put/take操作,所以進(jìn)行加鎖,看下面的第二步含義
        ????????fullyLock();
        ????????try?{
        ?????//獲取隊(duì)列元素個(gè)數(shù)size
        ????????????int?size?=?count.get();
        ?????//創(chuàng)建大小為size的object數(shù)組,之所以為Object類型是因?yàn)镺bject對象的范圍最大,什么類型都可以裝下
        ????????????Object[]?a?=?new?Object[size];
        ????????????int?k?=?0;
        ?????//循環(huán)遍歷隊(duì)列的每一個(gè)元素,將其裝入到數(shù)組object里面
        ????????????for?(Node?p?=?head.next;?p?!=?null;?p?=?p.next)
        ????????????????a[k++]?=?p.item;
        ????????????return?a;
        ????????}?finally?{
        ?????//最后進(jìn)行釋放對應(yīng)的鎖,其實(shí)這里你也可以學(xué)到很多東西的,比如說加鎖,解鎖操作,為啥要放到finally語句塊呢等等等
        ?????//都會潛移默化的指導(dǎo)你編碼的過程
        ????????????fullyUnlock();
        ????????}
        ????}
        //第二步,注釋已經(jīng)很好的說明了這個(gè)方法的含義,就是阻止put和take操作的,所以進(jìn)行獲取對應(yīng)的鎖進(jìn)行加鎖操作
        ?????/**
        ?????*?Locks?to?prevent?both?puts?and?takes.
        ?????*/
        ????void?fullyLock()?{
        ????????putLock.lock();
        ????????takeLock.lock();
        ????}

        2.11,方法總結(jié)

        這里自己沒有對隊(duì)列的poll()方法,offer()方法進(jìn)行分析,是因?yàn)樗蛅ake(),add()方法的分析過程都太一樣了,至于一點(diǎn)點(diǎn)差別,你可以去自己看下源碼哈,這里由于篇幅的問題就不過多介紹了,其實(shí)整個(gè)方法的分析就是基于鏈表和數(shù)組的操作。不過這里沒有在方法的分析過程中去寫時(shí)間復(fù)雜度,不過,你看過vector源碼之后就知道如何分析了。

        三,總結(jié)一下

        3.1,思考一下

        文章的開頭拋出了下面的3個(gè)問題

        1.1,為什么要分析源碼? 那我這里在問下,你分析完這個(gè)集合源碼,學(xué)習(xí)到了什么?是不是有點(diǎn)啟發(fā)?

        1.2,分析源碼的好處是? 在分析的過程中,你學(xué)會了如何更加去編碼,或許你沒有意識到,但這是潛移默化的過程,相信你學(xué)習(xí)到了

        1.3,如何分析源碼? 在整個(gè)文章的閱讀過程中,想必你已經(jīng)學(xué)會了如何分析源碼了,從哪入手,這也是一種潛移默化的過程


        有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

        歡迎大家關(guān)注Java之道公眾號


        好文章,我在看??

        瀏覽 47
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            少妇喷水 | 日韩欧美中文字幕在线视频 | 高清黄片免费看 | 色色视频导航 | 成人毛片18女人免费视频 | 教官趴在双腿吸核花蜜水视频 | 搞逼网站视频 | 香蕉国产精品 | 青青操人人 | 色爱婷婷|