spring boot中使用java線程池ExecutorService


 

轉載自

分享一篇關於在spring boot中使用java線程池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");
      }
    });
  }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM