08.14 玩轉ThreadPoolExecutor及Future獲取Excel數據

導讀:創建線程池、Callable任務實現管理多任務讀取Excel中數據,純屬個人學習總結及實踐,不追求程序合理性或適不適用實際場景。

理論:

1、線程池之 ThreadPoolExecutor

1.1 創建

new ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); /<runnable> 參數最多的構造方法

參數說明:

int corePoolSize

核心池的大小,這個參數跟後面講述的線程池的實現原理有非常大的關係。在創建了線程池後,默認情況下,線程池中並沒有任何線程,而是等待有任務到來才創建線程去執行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預創建線程的意思,即在沒有任務到來之前就創建corePoolSize個線程或者一個線程。默認情況下,在創建了線程池後,線程池中的線程數為0,當有任務來之後,就會創建一個線程去執行任務,當線程池中的線程數目達到corePoolSize後,就會把到達的任務放到緩存隊列當中。

int maximumPoolSize,

線程池最大線程數,這個參數也是一個非常重要的參數,它表示在線程池中最多能創建多少個線程。

long keepAliveTime,

表示線程沒有任務執行時最多保持多久時間會終止。默認情況下,只有當線程池中的線程數大於corePoolSize時,keepAliveTime才會起作用,直到線程池中的線程數不大於corePoolSize,即當線程池中的線程數大於corePoolSize時,如果一個線程空閒的時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。但是如果調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大於corePoolSize時,keepAliveTime參數也會起作用,直到線程池中的線程數為0;

TimeUnit unit,

參數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性:

TimeUnit.DAYS; //天

TimeUnit.HOURS; //小時

TimeUnit.MINUTES; //分鐘

TimeUnit.SECONDS; //秒

TimeUnit.MILLISECONDS; //毫秒

TimeUnit.MICROSECONDS; //微妙

TimeUnit.NANOSECONDS; //納秒

BlockingQueue<runnable> workQueue/<runnable>

一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,一般來說,這裡的阻塞隊列有以下幾種選擇:

ArrayBlockingQueue; 基於數組的先進先出隊列,此隊列創建時必須指定大小;

LinkedBlockingQueue; 基於鏈表的先進先出隊列,如果創建時沒有指定此隊列大小,則默認為Integer.MAX_VALUE;

SynchronousQueue; 這個隊列比較特殊,它不會保存提交的任務,而是將直接新建一個線程來執行新來的任務。

ArrayBlockingQueue和PriorityBlockingQueue使用較少,一般使用LinkedBlockingQueue和Synchronous。線程池的排隊策略與BlockingQueue有關。

ThreadFactory threadFactory

線程工廠,主要用來創建線程;

RejectedExecutionHandler handler

表示當拒絕處理任務時的策略,有以下四種取值:

ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。

ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。

ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後重新嘗試執行任務(重複此過程)

ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

1.2 核心方法說明

  • execute()

這個方法是ThreadPoolExecutor的核心方法,通過這個方法可以向線程池提交一個任務,交由線程池去執行。

  • submit()

是在ExecutorService中聲明的方法,在AbstractExecutorService就已經有了具體的實現, 在ThreadPoolExecutor中並沒有對其進行重寫,這個方法也是用來向線程池提交任務的,但是它和execute()方法不同,它能夠返回任務執行的結果,看submit()方法的實現,會發現它實際上還是調用的execute()方法,只不過它利用了Future來獲取任務執行結果。

當創建線程池後,初始時,線程池處於RUNNING狀態;

  • shutdown() 如果調用了這個方法,則線程池處於SHUTDOWN狀態,此時線程池不能夠接受新的任務,它會等待所有任務執行完畢;
  • shutdownNow() 如果調用了這個方法,方法,則線程池處於STOP狀態,此時線程池不能接受新的任務,並且會去嘗試終止正在執行的任務,並且清空任務緩存 隊列,返回尚未執行的任務

當線程池處於SHUTDOWN或STOP狀態,並且所有工作線程已經銷燬,任務緩存隊列已經清空或執行結束後,線程池被設置為TERMINATED狀態。

1.3 描述

在java doc中,並不提倡我們直接使用ThreadPoolExecutor,而是使用Executors類中提供的幾個靜態方法來創建線程池:

Executors.newCachedThreadPool(); //創建將corePoolSize設置為0,將maximumPoolSize設置為Integer.MAX_VALUE,使用的SynchronousQueue,也就是說來了任務就創建線程運行,當線程空閒超過60秒,就銷燬線程。

Executors.newSingleThreadExecutor(); //創建將corePoolSize和maximumPoolSize都設置為1,也使用的LinkedBlockingQueue;

Executors.newFixedThreadPool(int); //創建固定容量大小的緩衝池 創建的線程池corePoolSize和maximumPoolSize值是相等的,它使用LinkedBlockingQueue;

2、Callable

位於java.util.concurrent包下,是個泛型接口,在它裡面也只聲明瞭一個方法:call(),其返回的類型就是傳遞進來的V類型,

怎麼使用Callable呢?一般情況下是配合ExecutorService來使用的,在ExecutorService接口中聲明瞭若干個submit方法的重載版本:

Future submit(Callable task);

3、Future

是個接口,對於具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成、獲取結果。

內部幾個方法說明:

cancel方法用來取消任務,如果取消任務成功則返回true,如果取消任務失敗則返回false。參數mayInterruptIfRunning表示是否允許取消正在執行卻沒有執行完畢的任務,如果設置true,則表示可以取消正在執行過程中的任務。如果任務已經完成,則無論mayInterruptIfRunning為true還是false,此方法肯定返回false,即如果取消已經完成的任務會返回false;如果任務正在執行,若mayInterruptIfRunning設置為true,則返回true,若mayInterruptIfRunning設置為false,則返回false;如果任務還沒有執行,則無論mayInterruptIfRunning為true還是false,肯定返回true。

isCancelled方法表示任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。

isDone方法表示任務是否已經完成,若任務完成,則返回true;

get()方法用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;

get(long timeout, TimeUnit unit)用來獲取執行結果,如果在指定時間內,還沒獲取到結果,就直接返回異常。

也就是說Future提供了三種功能:

1)判斷任務是否完成;

2)能夠中斷任務;

3)能夠獲取任務執行結果。

因為Future只是一個接口,所以是無法直接用來創建對象使用的,因此就有了下面的FutureTask。

4、FutureTask

RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實現了RunnableFuture接口。所以它既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值。

*********************************************************************** 黃金分割 ************************************************************************

實戰:設置線程池,池中核心線程5個,最多10個線程(超過的線程入隊裡侯著),空閒線程最多存活500毫秒,讀取本地excel文件(500多條數據),分多個任務去讀取,每個任務讀50條。開始放圖:

玩轉ThreadPoolExecutor及Future獲取Excel數據

玩轉ThreadPoolExecutor及Future獲取Excel數據

玩轉ThreadPoolExecutor及Future獲取Excel數據

玩轉ThreadPoolExecutor及Future獲取Excel數據

玩轉ThreadPoolExecutor及Future獲取Excel數據

有不妥之處還請指正。

關於ThreadLocal:

玩轉ThreadPoolExecutor及Future獲取Excel數據

玩轉ThreadPoolExecutor及Future獲取Excel數據


分享到:


相關文章: