本篇文章為大家展示了spring boot中怎么使用ExecutorService線程池,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
1. 認識java線程池
1.1 在什么情況下使用線程池?
1.單個任務處理的時間比較短
2.需處理的任務的數量大
1.2 使用線程池的好處:
1.減少在創建和銷毀線程上所花的時間以及系統資源的開銷
2.如不使用線程池,有可能造成系統創建大量線程而導致消耗完系統內存
1.3 線程池包括以下四個基本組成部分:
1、線程池管理器(ThreadPool):用于創建并管理線程池,包括 創建線程池,銷毀線程池,添加新任務;
2、工作線程(PoolWorker):線程池中線程,在沒有任務時處于等待狀態,可以循環的執行任務;
3、任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行,它主要規定了任務的入口,任務執行完后的收尾工作,任務的執行狀態等;
4、任務隊列(taskQueue):用于存放沒有處理的任務。提供一種緩沖機制。
1.4 線程池的核心參數
ThreadPoolExecutor 有四個構造方法,前三個都是調用最后一個(最后一個參數最全)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
// 都調用它
public ThreadPoolExecutor(// 核心線程數
int corePoolSize,
// 最大線程數
int maximumPoolSize,
// 閑置線程存活時間
long keepAliveTime,
// 時間單位
TimeUnit unit,
// 線程隊列
BlockingQueue<Runnable> workQueue,
// 線程工廠
ThreadFactory threadFactory,
// 隊列已滿,而且當前線程數已經超過最大線程數時的異常處理策略
RejectedExecutionHandler handler ) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}主要參數
corePoolSize:核心線程數
核心線程會一直存活,即使沒有任務需要執行
當線程數小于核心線程數時,即使有線程空閑,線程池也會優先創建新線程處理
設置allowCoreThreadTimeout=true(默認false)時,核心線程會超時關閉
maxPoolSize:最大線程數
當線程數>=corePoolSize,且任務隊列已滿時。線程池會創建新線程來處理任務
當線程數=maxPoolSize,且任務隊列已滿時,線程池會拒絕處理任務而拋出異常
keepAliveTime:線程空閑時間
當線程空閑時間達到keepAliveTime時,線程會退出,直到線程數量=corePoolSize
如果allowCoreThreadTimeout=true,則會直到線程數量=0
workQueue:一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,一般來說,這里的阻塞隊列有以下幾種選擇:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
關于阻塞隊列可以看這篇:java 阻塞隊列
threadFactory:線程工廠,主要用來創建線程;
rejectedExecutionHandler:任務拒絕處理器,兩種情況會拒絕處理任務:
當線程數已經達到maxPoolSize,切隊列已滿,會拒絕新任務
當線程池被調用shutdown()后,會等待線程池里的任務執行完畢,再shutdown。如果在調用shutdown()和線程池真正shutdown之間提交任務,會拒絕新任務
當拒絕處理任務時線程池會調用rejectedExecutionHandler來處理這個任務。如果沒有設置默認是AbortPolicy,會拋出異常。ThreadPoolExecutor類有幾個內部實現類來處理這類情況:
AbortPolicy 丟棄任務,拋運行時異常
CallerRunsPolicy 執行任務
DiscardPolicy 忽視,什么都不會發生
DiscardOldestPolicy 從隊列中踢出最先進入隊列(最后一個執行)的任務
實現RejectedExecutionHandler接口,可自定義處理器
1.5 Java線程池 ExecutorService
Executors.newCachedThreadPool 創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
Executors.newFixedThreadPool 創建一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待。
Executors.newScheduledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。
Executors.newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
備注:Executors只是一個工廠類,它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor這兩個類的實例。
1.6 ExecutorService有如下幾個執行方法
executorService.execute(Runnable);這個方法接收一個Runnable實例,并且異步的執行
executorService.submit(Runnable)
executorService.submit(Callable)
executorService.invokeAny(…)
executorService.invokeAll(…)
execute(Runnable)
這個方法接收一個Runnable實例,并且異步的執行
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();submit(Runnable)
submit(Runnable)和execute(Runnable)區別是前者可以返回一個Future對象,通過返回的Future對象,我們可以檢查提交的任務是否執行完畢,請看下面執行的例子:
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
future.get(); //returns null if the task has finished correctly.submit(Callable)
submit(Callable)和submit(Runnable)類似,也會返回一個Future對象,但是除此之外,submit(Callable)接收的是一個Callable的實現,Callable接口中的call()方法有一個返回值,可以返回任務的執行結果,而Runnable接口中的run()方法是void的,沒有返回值。請看下面實例:
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});
System.out.println("future.get() = " + future.get());如果任務執行完成,future.get()方法會返回Callable任務的執行結果。注意,future.get()方法會產生阻塞。
invokeAny(…)
invokeAny(…)方法接收的是一個Callable的集合,執行這個方法不會返回Future,但是會返回所有Callable任務中其中一個任務的執行結果。這個方法也無法保證返回的是哪個任務的執行結果,反正是其中的某一個。
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();invokeAll(…)
invokeAll(…)與 invokeAny(…)類似也是接收一個Callable集合,但是前者執行之后會返回一個Future的List,其中對應著每個Callable任務執行后的Future對象。
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
executorService.shutdown();2. 在springBoot中使用java線程池ExecutorService
2.1 springBoot 的使用配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 數據收集配置,主要作用在于Spring啟動時自動加載一個ExecutorService對象.
* @author Bruce
* @date 2017/2/22
* update by Cliff at 2027/11/03
*/
@Configuration
public class ThreadPoolConfig {
@Bean
public ExecutorService getThreadPool(){
return Executors.newFixedThreadPool();
}
}2.2 使用
在@service 中注入 ExecutorService 然后就可以直接用了。
@Autowired
private ExecutorService executorService;
public void test(){
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
}上述內容就是spring boot中怎么使用ExecutorService線程池,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。