天天看點

java線程池架構原理分析

java線程池架構原理分析

線程池:裝有線程的池子,我們可以把要執行的多線程交給線程池來處理,和連接配接池的概念一樣,通過維護一定數量的線程池來達到多個線程的複用。

線程池的好處:不用線程池的話,每個線程都要通過new Thread(xxRunnable).start()的方式來建立并運作一個線程,線程少的話這不會是問題,而真實環境可能會開啟多個線程讓系統和程式達到最佳效率,當線程數達到一定數量就會耗盡系統的CPU和記憶體資源,也會造成GC頻繁收集和停頓,因為每次建立和銷毀一個線程都是要消耗系統資源的,如果為每個任務都建立線程這無疑是一個很大的性能瓶頸。是以,線程池中的線程複用極大節省了系統資源,當線程一段時間不再有任務處理時它也會自動銷毀,而不會長駐記憶體。

線程池核心類:ThreadPoolExecutor

首先看看線程池類的主要參數有哪些?

java線程池架構原理分析
  • corePoolSize:線程池的核心大小,也可以了解為最小的線程池大小。
  • maximumPoolSize:最大線程池大小。
  • keepAliveTime:空餘線程存活時間,指的是超過corePoolSize的空餘線程達到多長時間才進行銷毀。
  • unit:銷毀時間機關。
  • workQueue:存儲等待執行線程的工作隊列。
  • threadFactory:建立線程的工廠,一般用預設即可。
  • handler:拒絕政策,當工作隊列、線程池全已滿時如何拒絕新任務,預設抛出異常。

線程池工作流程:

1、如果線程池中的線程小于corePoolSize時就會建立新線程直接執行任務。

2、如果線程池中的線程大于corePoolSize時就會暫時把任務存儲到工作隊列workQueue中等待執行。

3、如果工作隊列workQueue也滿時:當線程數小于最大線程池數maximumPoolSize時就會建立新線程來處理,而線程數大于等于最大線程池數maximumPoolSize時就會執行拒絕政策。

線程池分類:

Executors是jdk裡面提供的建立線程池的工廠類,它預設提供了4種常用的線程池應用,不必去重複構造。

  • newFixedThreadPool

    固定線程池,核心線程數和最大線程數固定相等,而空閑存活時間為0毫秒,說明此參數也無意義,工作隊列為最大為Integer.MAX_VALUE大小的阻塞隊列。當執行任務時,如果線程都很忙,就會丢到工作隊列等有空閑線程時再執行,隊列滿就執行預設的拒絕政策

    java線程池架構原理分析
  • newCachedThreadPool

    帶緩沖線程池,從構造看核心線程數為0,最大線程數為Integer最大值大小,超過0個的空閑線程在60秒後銷毀,SynchronousQueue這是一個直接送出的隊列,意味着每個新任務都會有線程來執行,如果線程池有可用線程則執行任務,沒有的話就建立一個來執行,線程池中的線程數不确定,一般建議執行速度較快較小的線程,不然這個最大線程池邊界過大容易造成記憶體溢出。

    java線程池架構原理分析
  • newSingleThreadExecutor

    單線程線程池,核心線程數和最大線程數均為1,空閑線程存活0毫秒同樣無意思,意味着每次隻執行一個線程,多餘的先存儲到工作隊列,一個一個執行,保證了線程的順序執行

    java線程池架構原理分析
  • newScheduledThreadPool

    排程線程池,即按一定的周期執行任務,即定時任務,對ThreadPoolExecutor進行了包裝而已

    java線程池架構原理分析

拒絕政策

  • AbortPolicy 簡單粗暴,直接抛出拒絕異常,這也是預設的拒絕政策。
    java線程池架構原理分析
    java線程池架構原理分析
  • CallerRunsPolicy 如果線程池未關閉,則會在調用者線程中直接執行新任務,這會導緻主線程送出線程性能變慢。
    java線程池架構原理分析
  • DiscardPolicy 從方法看沒做任務操作,即表示不處理新任務,即丢棄。
    java線程池架構原理分析
  • DiscardOldestPolicy 抛棄最老的任務,就是從隊列取出最老的任務然後放入新的任務進行執行。        
    java線程池架構原理分析

如何送出線程

1.定義一個固定大小的線程池

ExecutorService es = Executors.newFixedThreadPool(3);

2.送出一個線程

es.submit(xxRunnble); 或

 es.execute(xxRunnble);

3. submit和execute差別:

execute沒有傳回值,如果不需要知道線程的結果就使用execute方法,性能會好很多。

submit傳回一個Future對象,如果想知道線程結果就使用submit送出,而且它能在主線程中通過Future的get方法捕獲線程中的異常。

es.shutdown(); :不再接受新的任務,之前送出的任務等執行結束再關閉線程池。

es.shutdownNow();:不再接受新的任務,試圖停止池中的任務再關閉線程池,傳回所有未處理的線程list清單。