
在开发中我们一般都是使用JUC包中的ThreadPoolExecutor的类,但在Springboot项目环境中可以使用ThreadPoolTaskExecutor类完成线程池的声明定义,且还可以使用@Async注解标注在接口实现方法上说明该逻辑异步处理。但是我们在使用的时候务必要进行相应环境配置,否则会存在一些问题,如默认值corePoolSize=1就相当于单线程,queyeCapacity=Integer.MAX_VALUE容易导致OOM问题等。
一、声明线程配置说明:可以在应用配置直接添加配置属性,我是独立到单独配置文件thread-pool.properties中
#配置核心线程数 thread-pool.corePoolSize = 4 # 配置最大线程数 thread-pool.maxPoolSize = 100 # 配置队列大小 thread-pool.queueCapacity = 500 # 线程最多存活时间/s thread-pool.keepAliveSeconds = 120 # 配置线程池中的线程的名称前缀 thread-pool.threadNamePrefix = my-thread-二、配置属性读取
声明一个配置属性对应的javabean,使用@ConfigurationProperties完成配置读取
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "thread-pool")
public class MyThreadPoolProperties {
private int corePoolSize;
private int maxPoolSize;
private int queueCapacity;
private String threadNamePrefix;
private int keepAliveSeconds;
}
三、声明线程池实例bean并设置属性
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@PropertySource(name="thread-pool",value = {"classpath:thread-pool.properties"})
@EnableConfigurationProperties(MyThreadPoolProperties.class)
public class MyThreadPoolConfiguration {
@Bean("myThreadExecutor")
public ThreadPoolTaskExecutor myThreadExecutor(MyThreadPoolProperties properties){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(properties.getCorePoolSize());
executor.setMaxPoolSize(properties.getMaxPoolSize());
executor.setQueueCapacity(properties.getQueueCapacity());
executor.setThreadNamePrefix(properties.getThreadNamePrefix());
executor.setKeepAliveSeconds(properties.getKeepAliveSeconds());
// 拒绝策略,交给调用这线程处理
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
四、验证业务中线程池的使用
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RestController
@RequestMapping("/api/pools")
public class TestThreadPoolController {
@Autowired
@Qualifier("myThreadExecutor")
private ThreadPoolTaskExecutor executor;
@GetMapping("/test1")
public String test1() throws ExecutionException, InterruptedException {
// 无返回值
executor.execute(() -> System.out.println("任务被执行了"));
// 有返回值
Future result = executor.submit(() -> "同步任务执行成功");
System.out.println(result.get());
return "SUCCESS";
}
}
五、验证使用@Async注解标注异步任务
import com.imk.cases.exceptions.handling.util.AppContextUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
// 启动异步任务和定时任务
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class CaseExceptionHandlingApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(CaseExceptionHandlingApplication.class, args);
AppContextUtils.setApplicationContext(applicationContext);
}
}
// 定义一个实现方法验证
// 每5s执行一次,使用自定义的线程池
@Scheduled(cron = "*/5 * * * * ?")
@Async("myThreadExecutor")
public void test2(){
System.out.println("myThreadExecutor test2");
}
六、总结
线程池的工作机制原理:
jdk中提供了 4 种拒绝策略实现:
关于线程池更多知识请学习JUC中线程池相关知识。