<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 38 線程池源碼面試題 ## 引導語 線程池在日常面試中占比很大,主要是因為線程池內容涉及的知識點較廣,比如涉及到隊列、線程、鎖等等,所以很多面試官喜歡把線程池作為問題的起點,然后延伸到其它內容,由于我們專欄已經說過隊列、線程、鎖面試題了,所以本章面試題還是以線程池為主。 ### 1:說說你對線程池的理解? 答:答題思路從大到小,從全面到局部,總的可以這么說,線程池結合了鎖、線程、隊列等元素,在請求量較大的環境下,可以多線程的處理請求,充分的利用了系統的資源,提高了處理請求的速度,細節可以從以下幾個方面闡述: 1. ThreadPoolExecutor 類結構; 2. ThreadPoolExecutor coreSize、maxSize 等重要屬性; 3. Worker 的重要作用; 4. submit 的整個過程。 通過以上總分的描述,應該可以說清楚對線程池的理解了,如果是面對面面試的話,可以邊說邊畫出線程池的整體架構圖(見《ThreadPoolExecutor 源碼解析》)。 ### 2:ThreadPoolExecutor、Executor、ExecutorService、Runnable、Callable、FutureTask 之間的關系? 答:以上 6 個類可以分成兩大類:一種是定義任務類,一種是執行任務類。 1. 定義任務類:Runnable、Callable、FutureTask。Runnable 是定義無返回值的任務,Callable 是定義有返回值的任務,FutureTask 是對 Runnable 和 Callable 兩種任務的統一,并增加了對任務的管理功能; 2. 執行任務類:ThreadPoolExecutor、Executor、ExecutorService。Executor 定義最基本的運行接口,ExecutorService 是對其功能的補充,ThreadPoolExecutor 提供真正可運行的線程池類,三個類定義了任務的運行機制。 日常的做法都是先根據定義任務類定義出任務來,然后丟給執行任務類去執行。 ### 3:說一說隊列在線程池中起的作用? 答:作用如下: 1. 當請求數大于 coreSize 時,可以讓任務在隊列中排隊,讓線程池中的線程慢慢的消費請求,實際工作中,實際線程數不可能等于請求數,隊列提供了一種機制讓任務可排隊,起一個緩沖區的作用; 2. 當線程消費完所有的線程后,會阻塞的從隊列中拿數據,通過隊列阻塞的功能,使線程不消亡,一旦隊列中有數據產生后,可立馬被消費。 ### 4:結合請求不斷增加時,說一說線程池構造器參數的含義和表現? 答:線程池構造器各個參數的含義如下: 1. coreSize 核心線程數; 2. maxSize 最大線程數; 3. keepAliveTime 線程空閑的最大時間; 4. queue 有多種隊列可供選擇,比如:1:SynchronousQueue,為了避免任務被拒絕,要求線程池的 maxSize 無界,缺點是當任務提交的速度超過消費的速度時,可能出現無限制的線程增長;2:LinkedBlockingQueue,無界隊列,未消費的任務可以在隊列中等待;3:ArrayBlockingQueue,有界隊列,可以防止資源被耗盡; 5. 線程新建的 ThreadFactory 可以自定義,也可以使用默認的 DefaultThreadFactory,DefaultThreadFactory 創建線程時,優先級會被限制成 NORM_PRIORITY,默認會被設置成非守護線程; 6. 在 Executor 已經關閉或對最大線程和最大隊列都使用飽和時,可以使用 RejectedExecutionHandler 類進行異常捕捉,有如下四種處理策略:ThreadPoolExecutor.AbortPolicy、ThreadPoolExecutor.DiscardPolicy、ThreadPoolExecutor.CallerRunsPolicy、ThreadPoolExecutor.DiscardOldestPolicy。 當請求不斷增加時,各個參數起的作用如下: 1. 請求數 < coreSize:創建新的線程來處理任務; 2. coreSize <= 請求數 && 能夠成功入隊列:任務進入到隊列中等待被消費; 3. 隊列已滿 && 請求數 < maxSize:創建新的線程來處理任務; 4. 隊列已滿 && 請求數 >= maxSize:使用 RejectedExecutionHandler 類拒絕請求。 ### 5:coreSize 和 maxSize 可以動態設置么,有沒有規則限制? 答:一般來說,coreSize 和 maxSize 在線程池初始化時就已經設定了,但我們也可以通過 setCorePoolSize、setMaximumPoolSize 方法動態的修改這兩個值。 setCorePoolSize 的限制見如下源碼: ``` // 如果新設置的值小于 coreSize,多余的線程在空閑時會被回收(不保證一定可以回收成功) // 如果大于 coseSize,會新創建線程 public void setCorePoolSize(int corePoolSize) { if (corePoolSize < 0) throw new IllegalArgumentException(); int delta = corePoolSize - this.corePoolSize; this.corePoolSize = corePoolSize; // 活動的線程大于新設置的核心線程數 if (workerCountOf(ctl.get()) > corePoolSize) // 嘗試將可以獲得鎖的 worker 中斷,只會循環一次 // 最后并不能保證活動的線程數一定小于核心線程數 interruptIdleWorkers(); // 設置的核心線程數大于原來的核心線程數 else if (delta > 0) { // 并不清楚應該新增多少線程,取新增核心線程數和等待隊列數據的最小值,夠用就好 int k = Math.min(delta, workQueue.size()); // 新增線程直到k,如果期間等待隊列空了也不會再新增 while (k-- > 0 && addWorker(null, true)) { if (workQueue.isEmpty()) break; } } } ``` setMaximumPoolSize 的限制見如下源碼: ``` // 如果 maxSize 大于原來的值,直接設置。 // 如果 maxSize 小于原來的值,嘗試干掉一些 worker public void setMaximumPoolSize(int maximumPoolSize) { if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) throw new IllegalArgumentException(); this.maximumPoolSize = maximumPoolSize; if (workerCountOf(ctl.get()) > maximumPoolSize) interruptIdleWorkers(); } ``` ### 6:說一說對于線程空閑回收的理解,源碼中如何體現的? 答:空閑線程回收的時機:如果線程超過 keepAliveTime 時間后,還從阻塞隊列中拿不到任務(這種情況我們稱為線程空閑),當前線程就會被回收,如果 allowCoreThreadTimeOut 設置成 true,core thread 也會被回收,直到還剩下一個線程為止,如果 allowCoreThreadTimeOut 設置成 false,只會回收非 core thread 的線程。 線程在任務執行完成之后,之所有沒有消亡,是因為阻塞的從隊列中拿任務,在 keepAliveTime 時間后都沒有拿到任務的話,就會打斷阻塞,線程直接返回,線程的生命周期就結束了,JVM 會回收掉該線程對象,所以我們說的線程回收源碼體現就是讓線程不在隊列中阻塞,直接返回了,可以見 ThreadPoolExecutor 源碼解析章節第三小節的源碼解析。 ### 7:如果我想在線程池任務執行之前和之后,做一些資源清理的工作,可以么,如何做? 答:可以的,ThreadPoolExecutor 提供了一些鉤子函數,我們只需要繼承 ThreadPoolExecutor 并實現這些鉤子函數即可。在線程池任務執行之前實現 beforeExecute 方法,執行之后實現 afterExecute 方法。 ### 8:線程池中的線程創建,拒絕請求可以自定義實現么?如何自定義? 答:可以自定義的,線程創建默認使用的是 DefaultThreadFactory,自定義話的只需要實現 ThreadFactory 接口即可;拒絕請求也是可以自定義的,實現 RejectedExecutionHandler 接口即可;在 ThreadPoolExecutor 初始化時,將兩個自定義類作為構造器的入參傳遞給 ThreadPoolExecutor 即可。 ### 9:說說你對 Worker 的理解? 答:詳見《ThreadPoolExecutor 源碼解析》中 1.4 小節。 ### 10:說一說 submit 方法執行的過程? 答:詳見《ThreadPoolExecutor 源碼解析》中 2 小節。 ### 11:說一說線程執行任務之后,都在干啥? 答:線程執行任務完成之后,有兩種結果: 1. 線程會阻塞從隊列中拿任務,沒有任務的話無限阻塞; 2. 線程會阻塞從隊列中拿任務,沒有任務的話阻塞一段時間后,線程返回,被 JVM 回收。 ### 12:keepAliveTime 設置成負數或者是 0,表示無限阻塞? 答:這種是不對的,如果 keepAliveTime 設置成負數,在線程池初始化時,就會直接報 IllegalArgumentException 的異常,而設置成 0,隊列如果是 LinkedBlockingQueue 的話,執行 workQueue.poll (keepAliveTime, TimeUnit.NANOSECONDS) 方法時,如果隊列中沒有任務,會直接返回 null,導致線程立馬返回,不會無限阻塞。 如果想無限阻塞的話,可以把 keepAliveTime 設置的很大,把 TimeUnit 也設置的很大,接近于無限阻塞。 ### 13:說一說 Future.get 方法是如何拿到線程的執行結果的? 答:我們需要明確幾點: 1. submit 方法的返回結果實際上是 FutureTask,我們平時都是針對接口編程,所以使用的是 Future.get 來拿到線程的執行結果,實際上是 FutureTask.get ,其方法底層是從 FutureTask 的 outcome 屬性拿值的; 2. 《ThreadPoolExecutor 源碼解析》中 2 小節中詳細說明了 submit 方法最終會把線程的執行結果賦值給 outcome。 結合 1、2,當線程執行完成之后,自然就可以從 FutureTask 的 outcome 屬性中拿到值。 ### 14:總結 如果我們弄清楚 ThreadPoolExecutor 的原理之后,線程池的面試題都很簡單,所以建議大家多看看 《ThreadPoolExecutor 源碼解析》這小節。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看