1.JAVA多線程(二十)Java多線程之FixedThreadPool可重用固定線程數的線程池
1.1 可重用固定線程數的線程池FixedThreadPool
可重用固定線程數的線程池FixedThreadPool特點是:只有核心線程,不會被回收、線程數量固定、任務隊列無大小限制(超出的線程任務會在隊列中等待),通過源代碼查看FixedThreadPool實現:
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue, using the provided
* ThreadFactory to create new threads when needed. At any point,
* at most {@code nThreads} threads will be active processing
* tasks. If additional tasks are submitted when all threads are
* active, they will wait in the queue until a thread is
* available. If any thread terminates due to a failure during
* execution prior to shutdown, a new one will take its place if
* needed to execute subsequent tasks. The threads in the pool will
* exist until it is explicitly {@link ExecutorService#shutdown
* shutdown}.
*
* @param nThreads the number of threads in the pool
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
在FixedThreadPool實現中:
- corePoolSize && maximumPoolSize,核心線程數和允許最大的線程數一致,可以指定無限大,在資源有限的情況下容易引起OOM異常。
- keepAliveTime => keepAliveTime爲0,意味着多餘的空閒線程會被立即終止。
- workQueue => 採用無界隊列LinkedBlockingQueue作爲線程池的工作隊列(隊列的容量爲Integer.MAX_VALUE),會在循環中反覆從LinkedBlockingQueue獲取任務來執行。
1.2 FixedThreadPool使用樣例
FixedThreadPool線程池使用LinkedBlockingQueue作爲線程池的工作隊列會對線程池帶來如下影響:
- 當線程池中的線程數達到corePoolSize核心線程數後,新任務將在無界隊列中等待,因此線程池中的線程數不會超過corePoolSize核心線程數。
- 使用無界隊列,運行中的FixedThreadPool不會拒絕任務,(未執行方法shutdown()或shutdownNow(),不會調用RejectedExecutionHandler.rejectedExecution方法),在任務比較多的時候會導致 OOM(內存溢出)。
package com.yuanxw.chapter20;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class FixedThreadPoolExample {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(5);
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
for (int i = 0; i < 10; i++) {
executorService.execute(()->{
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(String.format("線程【%s】正在工作>>>>", Thread.currentThread().getName()));
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
TimeUnit.SECONDS.sleep(5);
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
// corePoolSize 等於 maximumPoolSize,因此應用程序不會結束,需要調用executorService.shutdown()方法,關閉線程池。
executorService.shutdown();
}
}
執行結果:
獲得活動的線程評估數:0
線程【pool-1-thread-2】正在工作>>>>
線程【pool-1-thread-3】正在工作>>>>
獲得活動的線程評估數:5
線程【pool-1-thread-1】正在工作>>>>
獲得活動的線程評估數:4
線程【pool-1-thread-5】正在工作>>>>
獲得活動的線程評估數:5
獲得活動的線程評估數:5
線程【pool-1-thread-4】正在工作>>>>
獲得活動的線程評估數:5
線程【pool-1-thread-4】正在工作>>>>
線程【pool-1-thread-3】正在工作>>>>
線程【pool-1-thread-2】正在工作>>>>
線程【pool-1-thread-5】正在工作>>>>
獲得活動的線程評估數:5
線程【pool-1-thread-1】正在工作>>>>
獲得活動的線程評估數:5
獲得活動的線程評估數:5
獲得活動的線程評估數:5
獲得活動的線程評估數:4
獲得活動的線程評估數:0
FixedThreadPool 的 execute()方法的執行示意圖(該圖片來源:《Java 併發編程的藝術》):
- 如果當前運行的線程數小於 corePoolSize, 如果再來新任務的話,就創建新的線程來執行任務;
- 當前運行的線程數等於 corePoolSize 後, 如果再來新任務的話,會將任務加入 LinkedBlockingQueue;
- 線程池中的線程執行完當前的任務後,會在循環中反覆從 LinkedBlockingQueue 中獲取任務來執行;
– 以上爲《JAVA多線程(二十)Java多線程之FixedThreadPool可重用固定線程數的線程池》,如有不當之處請指出,我後續逐步完善更正,大家共同提高。謝謝大家對我的關注。
——厚積薄發(yuanxw)