SpringBoot線程池使用詳解

前提摘要:

    基於Springboot 2.1.4.RELEASE

 

▎ 配置TaskExecutor

import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class ThreadPoolConfig {

	@Bean
	public TaskExecutor taskExecutor() {

		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

		// 設置核心線程數
		executor.setCorePoolSize(5);

		// 設置最大線程數
		executor.setMaxPoolSize(10);

		// 設置隊列容量
		executor.setQueueCapacity(5);

		// 設置線程活躍時間,單位秒
		executor.setKeepAliveSeconds(60);

		// 設置核心線程超時回收
		executor.setAllowCoreThreadTimeOut(true);

		// 設置默認線程名稱
		executor.setThreadNamePrefix("IThread-");

		// 設置拒絕策略
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());

		return executor;

	}
}

▎ 參數解讀

● CorePoolSize

核心線程數,核心線程會一直存活,即使沒有任務需要處理。當線程數小於核心線程數時,即使現有的線程空閒,線程池也會優先創建新線程來處理任務,而不是直接交給現有的線程處理。

核心線程在allowCoreThreadTimeout被設置爲true時會超時退出,默認情況下不會退出。

● MaxPoolSize

當線程數大於或等於核心線程,且任務隊列已滿時,線程池會創建新的線程,直到線程數量達到maxPoolSize。如果線程數已等於maxPoolSize,且任務隊列已滿,則已超出線程池的處理能力,線程池會拒絕處理任務而拋出異常。

● queueCapacity
任務隊列容量。從maxPoolSize的描述上可以看出,任務隊列的容量會影響到線程的變化,因此任務隊列的長度也需要恰當的設置。

● keepAliveTime

當線程空閒時間達到keepAliveTime,該線程會退出,直到線程數量等於corePoolSize。如果allowCoreThreadTimeout設置爲true,則所有線程均會退出直到線程數量爲0。

● allowCoreThreadTimeout
是否允許核心線程空閒退出,默認值爲false。

● RejectedExecutionHandler

拒絕策略:當線程數大於MaxPoolSize+queueCapacity被觸發:

  ☞ CallerRunsPolicy - 當觸發拒絕策略,只要線程池沒有關閉的話,則使用調用線程直接運行任務。一般併發比較小,性能要求不高,不允許失敗。但是,由於調用者自己運行任務,如果任務提交速度過快,可能導致程序阻塞,性能效率上必然的損失較大

    ☞ AbortPolicy - 丟棄任務,並拋出拒絕執行 RejectedExecutionException 異常信息。線程池默認的拒絕策略。必須處理好拋出的異常,否則會打斷當前的執行流程,影響後續的任務執行。

  ☞ DiscardPolicy - 直接丟棄,其他啥都沒有

  ☞ DiscardOldestPolicy -  當觸發拒絕策略,只要線程池沒有關閉的話,丟棄阻塞隊列 workQueue 中最老的一個任務,並將新任務加入

 

▎ 線程池執行流程圖   圖片來源:https://www.cnblogs.com/yw0219/p/8810956.html

 

▎ 案例: 使用AbortPolicy拒絕策略,模擬高併發觸發異常

☞ TaskExecutor配置

@Bean
public TaskExecutor taskExecutor() {
	ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
	// 設置核心線程數
	executor.setCorePoolSize(5);
	// 設置最大線程數
	executor.setMaxPoolSize(10);
	// 設置隊列容量
	executor.setQueueCapacity(5);
	// 設置線程活躍時間,單位秒
	executor.setKeepAliveSeconds(60);
	// 設置核心線程超時回收
	executor.setAllowCoreThreadTimeOut(true);
	// 設置默認線程名稱
	executor.setThreadNamePrefix("IThread-");
	// 設置拒絕策略
	executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
	return executor;
}

☞ 創建異步任務

ExecutorService

public interface ExecutorService {
	public void exec();
}

ExecutorServiceImpl

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.mote.service.ExecutorService;

@Service("executorService")
public class ExecutorServiceImpl implements ExecutorService {

	private Logger log = LoggerFactory.getLogger(getClass());

	@Override
	@Async
	public void exec() {
		log.info(Thread.currentThread().getName() + "開始執行");

		try {
			// 模擬業務處理耗時
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		log.info("<<<<<<<<<<<<<<<<線程執行完畢>>>>>>>>>>>>>>>>");
	}

}

☞ 編寫Controller,調用異步任務

ExecutorController

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mote.service.ExecutorService;

@RestController
public class ExecutorController {

	@Autowired
	private ExecutorService executorService;

	@GetMapping("/executor")
	public String executor() {
		try {
			executorService.exec();
			return "success";
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "error";
	}
}

 

☞ 打開瀏覽器,訪問Controller接口,不斷刷新模擬高併發,觀察返回結果,如果出現error說明策略被觸發了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章