可以使用ThreadPoolExecutor來完成。然而它不會做你期望的事情。以下構造函數可用於創建ThreadPoolExecutor
。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
讓我打破它的行爲記錄。提交任務時
- 如果
poolSize
小於corePoolSize
,即使存在空閒線程,也會創建新線程。
- 如果
poolSize
等於corePoolSize
,則將任務添加到隊列中。在隊列耗盡之前它不會創建新線程。
- 如果
workQueue
用盡,則創建新線程直至poolSize
變爲maximumPoolSize
。
- 如果
poolSize
等於maximumPoolSize
拋RejectedExecutionException
所以現在假設我們設定的核心大小爲5,最大尺寸爲10,100個提交任務。如果我們使用Executors類創建池對象,則不會發生任何事情。因爲它創建的池使用LinkedBlockingQueue,默認的構造函數將隊列容量設置爲Integer.MAX_VALUE(2147483647
)。
以下是Executors
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
默認構造在LinkedBlockingQueue
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
...
選項的代碼來創建ThreadPoolExecutor
直接仍然存在,但是這是沒有太大的幫助。讓我們檢查一下。假設我們使用下面的代碼創建了ThreadPoolExecutor
對象。
ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(MAX_QUEUE_SIZE);
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, IDLE_LIFE_TIME, TimeUnit.SECONDS, workQueue);
其中MAX_QUEUE_SIZE
是10.可以提交的最大任務數可以通過下面的公式找到。
MAX_TASKS = MAX_POOL_SIZE + WORK_QUEUE_CAPACITY
所以,如果最大池大小爲10,工作隊列大小也是10,那麼21日的任務將被拒絕,如果沒有線程是免費的。
請務必記住,它不會給我們預期的行爲。由於線程僅在線程數比corePoolSize
多。只有workQueue
已用盡,線程池纔會增加超過corePoolSize
。
所以maxPoolSize
是一個故障安全選項,以避免隊列耗盡。而不是相反。最大池大小不是爲了殺死空閒線程。
如果我們設置的隊列大小太小,我們冒任務拒絕的風險。如果我們設置得太高,poolSize
將永遠不會穿越corePoolSize
。您可以探索ThreadPoolExecutor.setRejectedExecutionHandler。並且將被拒絕的任務另存爲一個單獨的隊列,一旦workQueue.capacity
週期性地變爲小於最大容量,該隊列將向workQueue
發送任務。但是,這似乎很多工作沒有相同的收益。
這不就是一個對象池的預期行爲? – 11thdimension
它可能是線程池的默認行爲。但就我而言,所有線程在高峯時間都處於活動狀態,在此之後,它們始終處於等待狀態,之後只有少數幾個將被使用。所以想知道是否有任何可以使用的Executor服務的其他設置。或者任何可以解決這種情況的其他實現。 – samo
如果你想爲每個作業創建一個新的線程,爲什麼你完全使用'ExecutorService'?如果你不這樣做,爲什麼你說的第一件事是? – EJP