Java面試經典題:線程池專題

來源:互聯網
上載者:User

標籤:ace   unp   thread   部分   拒絕策略   就會   注意   bsp   code   

1、什麼是線程池

線程池的基本思想是一種對象池,在程式啟動時就開闢一塊記憶體空間,裡面存放了眾多(未死亡)的線程,池中線程執行調度由池管理器來處理。當有線程任務時,從池中取一個,執行完成後線程對象歸池,這樣可以避免反覆建立線程對象所帶來的效能開銷,節省了系統的資源。

2、使用線程池的好處
  1. 減少了建立和銷毀線程的次數,每個背景工作執行緒都可以被重複利用,可執行多個任務。
  2. 運用線程池能有效控制線程最大並發數,可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個線程需要大約1MB記憶體,線程開的越多,消耗的記憶體也就越大,最後死機)。
  3. 對線程進行一些簡單的管理,比如:延時執行、定時迴圈執行的策略等,運用線程池都能進行很好的實現
3、線程池的主要組件

 

 

一個線程池包括以下四個基本組成部分:

  1. 線程池管理器(ThreadPool):用於建立並管理線程池,包括 建立線程池,銷毀線程池,添加新任務;
  2. 背景工作執行緒(WorkThread):線程池中線程,在沒有任務時處於等待狀態,可以迴圈的執行任務;
  3. 任務介面(Task):每個任務必須實現的介面,以供背景工作執行緒調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
  4. 任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
4、ThreadPoolExecutor類

講到線程池,要重點介紹java.uitl.concurrent.ThreadPoolExecutor類,ThreadPoolExecutor線程池中最核心的一個類,ThreadPoolExecutor在JDK中線程池常用類UML類別關係圖如下:

 

我們可以通過ThreadPoolExecutor來建立一個線程池

 

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);複製代碼
1. 建立一個線程池需要輸入幾個參數
  • corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會建立一個線程來執行任務,即使其他閒置基本線程能夠執行新任務也會建立線程,等到需要執行的任務數大於線程池基本大小時就不再建立。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前建立並啟動所有基本線程。
  • maximumPoolSize(線程池最大大小):線程池允許建立的最大線程數。如果隊列滿了,並且已建立的線程數小於最大線程數,則線程池會再建立新的線程執行任務。值得注意的是如果使用了無界的任務隊列這個參數就沒什麼效果。
  • runnableTaskQueue(任務隊列):用於儲存等待執行的任務的阻塞隊列。
  • ThreadFactory:用於設定建立線程的工廠,可以通過線程工廠給每個建立出來的線程設定更有意義的名字,Debug和定位問題時非常又協助。
  • RejectedExecutionHandler(拒絕策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。n AbortPolicy:直接拋出異常。
  • keepAliveTime(線程活動保持時間):線程池的背景工作執行緒空閑後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。
  • TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
2. 向線程池提交任務

我們可以通過execute()或submit()兩個方法向線程池提交任務,不過它們有所不同

  • execute()方法沒有傳回值,所以無法判斷任務知否被線程池執行成功
threadsPool.execute(new Runnable() {    @Override    public void run() {    // TODO Auto-generated method stub   }});複製代碼
  • submit()方法返回一個future,那麼我們可以通過這個future來判斷任務是否執行成功,通過future的get方法來擷取傳回值
try {     Object s = future.get();   } catch (InterruptedException e) {   // 處理中斷異常   } catch (ExecutionException e) {   // 處理無法執行任務異常   } finally {   // 關閉線程池   executor.shutdown();}複製代碼
3. 線程池的關閉

我們可以通過shutdown()或shutdownNow()方法來關閉線程池,不過它們也有所不同

  • shutdown的原理是只是將線程池的狀態設定成SHUTDOWN狀態,然後中斷所有沒有正在執行任務的線程。
  • shutdownNow的原理是遍曆線程池中的背景工作執行緒,然後逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法終止。shutdownNow會首先將線程池的狀態設定成STOP,然後嘗試停止所有的正在執行或暫停任務的線程,並返回等待執行任務的列表。
4. ThreadPoolExecutor執行的策略

 

 

  1. 線程數量未達到corePoolSize,則建立一個線程(核心線程)執行任務
  2. 線程數量達到了corePools,則將任務移入隊列等待
  3. 隊列已滿,建立線程(非核心線程)執行任務
  4. 隊列已滿,匯流排程數又達到了maximumPoolSize,就會由(RejectedExecutionHandler)拋出異常

建立線程 -> 達到核心數 -> 排入佇列 -> 建立線程(非核心) -> 達到最大數 -> 觸發拒絕策略

5. 四種拒絕策略
  1. AbortPolicy:不執行新任務,直接拋出異常,提示線程池已滿,線程池預設策略
  2. DiscardPolicy:不執行新任務,也不拋出異常,基本上為靜默模式。
  3. DisCardOldSetPolicy:將訊息佇列中的第一個任務替換為當前新進來的任務執行
  4. CallerRunPolicy:拒絕新任務進入,如果該線程池還沒有被關閉,那麼這個新的任務在執行線程中被調用)
5、Java通過Executors提供四種線程池
  1. CachedThreadPool():可緩衝線程池。
  • 線程數無限制
  • 有空閑線程則複用空閑線程,若無空閑線程則建立線程 一定程式減少頻繁建立/銷毀線程,減少系統開銷
  1. FixedThreadPool():定長線程池。
  • 可控制線程最大並發數(同時執行的線程數)
  • 超出的線程會在隊列中等待
  1. ScheduledThreadPool():
  • 定時線程池。
  • 支援定時及週期性任務執行。
  1. SingleThreadExecutor():單線程化的線程池。
  • 有且僅有一個背景工作執行緒執行任務
  • 所有任務按照指定順序執行,即遵循隊列的入隊出隊規則
1. newCachedThreadPool

newCachedThreadPool建立一個可緩衝線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則建立線程

public class ThreadPoolExecutorTest1 {public static void main(String[] args) {ExecutorService cachedThreadPool = Executors.newCachedThreadPool();for (int i = 0; i < 1000; i++) {final int index = i;try {Thread.sleep(index * 1000);} catch (Exception e) {e.printStackTrace();}cachedThreadPool.execute(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName()+":"+index);}});}}}複製代碼

 

 

2. newFixedThreadPool

newFixedThreadPool建立一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待,指定線程池中的線程數量和最大線程數量一樣,也就線程數量固定不變

範例程式碼如下

public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);// 每隔兩秒列印3個數for (int i = 0; i < 10; i++) {final int index = i;fixedThreadPool.execute(new Runnable() {public void run() {try {System.out.println(Thread.currentThread().getName()+":"+index);//三個線程並發Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}});}}}複製代碼

 

 

3. newscheduledThreadPool

newscheduledThreadPool建立一個定長線程池,支援定時及週期性任務執行。順延強制範例程式碼如下.表示延遲1秒後每3秒執行一次

public class ThreadPoolExecutorTest3 {public static void main(String[] args) {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);scheduledThreadPool.scheduleAtFixedRate(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() + ": delay 1 seconds, and excute every 3 seconds");}}, 1, 3, TimeUnit.SECONDS);// 表示延遲1秒後每3秒執行一次}}複製代碼

 

 

4. newSingleThreadExecutor

newSingleThreadExecutor建立一個單線程化的線程池,它只會用唯一的背景工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行

public class ThreadPoolExecutorTest4 {public static void main(String[] args) {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {final int index = i;singleThreadExecutor.execute(new Runnable() {public void run() {try {System.out.println(Thread.currentThread().getName() + ":" + index);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});}}}複製代碼

結果依次輸出,相當於順序執行各個任務。使用JDK內建的監控工具來監控我們建立的線程數量,運行一個不終止的線程,建立指定量的線程,來觀察

 

 

 



Java面試經典題:線程池專題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.