<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          和阿里P8大佬面試互懟了半小時(shí)的Fork/Join原理!

          共 3311字,需瀏覽 7分鐘

           ·

          2021-04-25 20:50


            點(diǎn)擊上方“JavaEdge”,關(guān)注公眾號(hào)

          設(shè)為“星標(biāo)”,好文章不錯(cuò)過(guò)!

          只聽(tīng)到P8大佬不急不慢問(wèn)道:談?wù)剬?duì)JDK并發(fā)工具的認(rèn)識(shí)?

                                  

          我開(kāi)始仔細(xì)梳理多年的并發(fā)八股文經(jīng)驗(yàn),道:
          線程池、Future、CompletableFuture和CompletionService這些并發(fā)工具都是幫助SE站在任務(wù)角度解決并發(fā)問(wèn)題,而非糾結(jié)于線程之間協(xié)作的細(xì)節(jié),比如線程之間如何實(shí)現(xiàn)等待、通知。

          • 簡(jiǎn)單并行任務(wù)
            線程池+Future 組合拳

          • 任務(wù)間有聚合關(guān)系
            AND、OR聚合,CompletableFuture 一招鮮

          • 批量的并行任務(wù)
            CompletionService 一把梭

          并發(fā)編程可分為三個(gè)層面問(wèn)題:分工、協(xié)作、互斥。

          當(dāng)關(guān)注于任務(wù)時(shí),你會(huì)發(fā)現(xiàn)你的視角已躍出并發(fā)編程細(xì)節(jié),而使用現(xiàn)實(shí)世界思維模式,類比現(xiàn)實(shí)世界的分工,其實(shí)線程池、Future、CompletableFuture和CompletionService都可列為分工問(wèn)題。

          • 簡(jiǎn)單并行任務(wù)聚合任務(wù)批量并行任務(wù)的現(xiàn)實(shí)的工作流程圖

          這三種任務(wù)模型,基本覆蓋日常工作中的并發(fā)場(chǎng)景,但其實(shí)還有一種“分治”任務(wù)模型。

          分治,分而治之,一種解決復(fù)雜問(wèn)題的思維方法和模式。把一個(gè)復(fù)雜問(wèn)題分解成多個(gè)相似的子問(wèn)題,然后再把子問(wèn)題分解成更小的子問(wèn)題,直到子問(wèn)題簡(jiǎn)單到可以直接求解。理論上解決每一個(gè)問(wèn)題都對(duì)應(yīng)著一個(gè)任務(wù),所以對(duì)于問(wèn)題的分治,實(shí)際上就是對(duì)于任務(wù)的分治。
                                                      

          P8 大佬直接開(kāi)問(wèn),那你說(shuō)說(shuō)什么是分治任務(wù)模型?
          分治任務(wù)模型可分為兩個(gè)階段:

          • 任務(wù)分解
            將任務(wù)迭代地分解為子任務(wù),直至子任務(wù)可計(jì)算出結(jié)果。將地區(qū)具體事務(wù)分屬各個(gè)地方行政官。

          • 結(jié)果合并

            逐層合并子任務(wù)的執(zhí)行結(jié)果,直至獲得最終結(jié)果。各地方行政官最終將治理成果匯報(bào)上級(jí)。


          就像官僚制度一樣:
                                            
          那你平時(shí)開(kāi)發(fā)是如何使用Fork/Join的?
                                                                
          我,我平時(shí)還真沒(méi)通過(guò)啊,就背過(guò)。還好這道題,我面試前也準(zhǔn)備了…

          Fork/Join是一個(gè)并行計(jì)算框架,以支持分治任務(wù)模型

          • Fork對(duì)應(yīng)分治任務(wù)模型里的任務(wù)分解

          • Join對(duì)應(yīng)結(jié)果合并

          Fork/Join計(jì)算框架主要包含兩部分:

          • 分治任務(wù)的線程池ForkJoinPool

          • 分治任務(wù)ForkJoinTask

          這倆的關(guān)系類似于 ThreadPoolExecutor 和 Runnable,都是提交任務(wù)到線程池,只不過(guò)分治任務(wù)有自己獨(dú)特的任務(wù)類型ForkJoinTask。

          ForkJoinTask

          JDK7 提供,一個(gè)抽象類,核心方法如下:

          • fork()
            異步執(zhí)行一個(gè)子任務(wù)

          • join()
            阻塞當(dāng)前線程來(lái)等待子任務(wù)的執(zhí)行結(jié)果

          ForkJoinTask有兩個(gè)子類——RecursiveAction和RecursiveTask,顯然都是用遞歸處理分治任務(wù)。這兩個(gè)子類都定義了抽象方法compute():

          • RecursiveAction#compute()無(wú)返回值

          • RecursiveTask#compute()有返回值

          注意到這倆類都是抽象類,使用要定義子類實(shí)現(xiàn)。
                                             


          只見(jiàn) P8 開(kāi)始冷笑,看來(lái)要問(wèn)源碼級(jí)別原理了!
                                      

          那你說(shuō)下Fork/Join的工作原理

          還好我知道阿里面試套路,凡是 java 工具,必問(wèn)深入的源碼。

          因?yàn)镕ork/Join的核心就是ForkJoinPool,讓我來(lái)深入講解ForkJoinPool原理。

          ThreadPoolExecutor本質(zhì)是個(gè)生產(chǎn)者-消費(fèi)者實(shí)現(xiàn),內(nèi)部有一個(gè)任務(wù)隊(duì)列,作為生產(chǎn)者和消費(fèi)者的通信媒介。ThreadPoolExecutor可以有多個(gè)工作線程,這些工作線程都共享一個(gè)任務(wù)隊(duì)列。

          ForkJoinPool本質(zhì)上也是一個(gè)生產(chǎn)者-消費(fèi)者的實(shí)現(xiàn),但更智能

          • ForkJoinPool工作原理圖

          ThreadPoolExecutor內(nèi)部只有一個(gè)任務(wù)隊(duì)列,而ForkJoinPool內(nèi)部有多個(gè)任務(wù)隊(duì)列,當(dāng)調(diào)用ForkJoinPool#invoke()submit()提交任務(wù)時(shí),F(xiàn)orkJoinPool把任務(wù)通過(guò)路由規(guī)則提交到一個(gè)任務(wù)隊(duì)列,如果任務(wù)在執(zhí)行過(guò)程中會(huì)創(chuàng)建出子任務(wù),那么子任務(wù)會(huì)提交到工作線程對(duì)應(yīng)的任務(wù)隊(duì)列。

          如果工作線程對(duì)應(yīng)的任務(wù)隊(duì)列空,是不是就沒(méi)活兒干了?
          No!ForkJoinPool有個(gè)“任務(wù)竊取”機(jī)制,若工作線程空閑了,它會(huì)“竊取”其他工作任務(wù)隊(duì)列里的任務(wù),例如剛才那個(gè)圖中,線程T2對(duì)應(yīng)任務(wù)隊(duì)列已空
                   
          那它會(huì)“竊取”線程T1對(duì)應(yīng)的任務(wù)隊(duì)列的任務(wù)。這樣所有工作線程都不會(huì)閑著。

          ForkJoinPool的任務(wù)隊(duì)列采用的是雙端隊(duì)列,工作線程正常獲取任務(wù)和“竊取任務(wù)”分別從任務(wù)隊(duì)列不同的端消費(fèi),這也能避免很多不必要的數(shù)據(jù)競(jìng)爭(zhēng)。

          ForkJoinPool支持任務(wù)竊取機(jī)制,能夠讓所有線程的工作量基本公平,不會(huì)出現(xiàn)線程有的很忙,有的一直在摸魚,所以性能很好,是個(gè)很公正的領(lǐng)導(dǎo)。
          Java8的Stream API里面并行流也是基于ForkJoinPool。
          默認(rèn),所有的并行流計(jì)算都共享一個(gè)ForkJoinPool,這個(gè)共享的ForkJoinPool的默認(rèn)線程數(shù)是CPU核數(shù);
          若所有并行流計(jì)算都是CPU密集型,完全沒(méi)有問(wèn)題,但若存在I/O密集型并行流計(jì)算,那很可能因?yàn)橐粋€(gè)很慢的I/O計(jì)算而拖慢整個(gè)系統(tǒng)的性能。所以建議用不同F(xiàn)orkJoinPool執(zhí)行不同類型的計(jì)算任務(wù)。

          參考

          • https://www.liaoxuefeng.com/article/1146802219354112


          往期推薦


          由于不知線程池的bug,某Java程序員叕被祭天

          程序員因重復(fù)記錄日志撐爆ELK被辭退!

          擁抱Kubernetes,再見(jiàn)了Spring Cloud

          JDK為何自己先破壞雙親委派模型?




          目前交流群已有 800+人,旨在促進(jìn)技術(shù)交流,可關(guān)注公眾號(hào)添加筆者微信邀請(qǐng)進(jìn)群



          喜歡文章,點(diǎn)個(gè)“在看、點(diǎn)贊、分享”素質(zhì)三連支持一下~

          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久亚洲AV成人无码国产精品 | 中文字第一页幕精品导航网站国产乱伦 | 黄片大全在线免费观看 | 黄色免费看日本 | 色五月综合网 |