Spring线程池之三:有返回值的线程池使用
1、配置
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; //该注解的locations已经被启用,现在只要是在环境中,都会优先加载 @Component @ConfigurationProperties(prefix = "sync.pool") public class SyncThreadPoolConfig { /**配置核心线程数*/ private int corePoolSize; /**配置最大线程数*/ private int maxPoolSize; /**活跃时间*/ private int keepAliveSeconds; /**配置队列大小*/ private int queueCapacity; public int getCorePoolSize() { return corePoolSize; } public void setCorePoolSize(int corePoolSize) { this.corePoolSize = corePoolSize; } public int getMaxPoolSize() { return maxPoolSize; } public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; } public int getKeepAliveSeconds() { return keepAliveSeconds; } public void setKeepAliveSeconds(int keepAliveSeconds) { this.keepAliveSeconds = keepAliveSeconds; } public int getQueueCapacity() { return queueCapacity; } public void setQueueCapacity(int queueCapacity) { this.queueCapacity = queueCapacity; } }
2、SyncThreadPoolConfiguration.java
@Configuration @ConditionalOnProperty(name = "sync.pool.enable", havingValue = "true") public class SyncThreadPoolConfiguration { private static final Logger LOG = LoggerFactory.getLogger(SyncThreadPoolConfiguration.class); @Autowired private SyncThreadPoolConfig config; // 配置属性类,见上面的代码 //同步线程池,如果不指定name值,则按methodName做beanName @Bean(name = "syncExceutor") public ThreadPoolTaskExecutor syncExceutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(config.getCorePoolSize()); executor.setMaxPoolSize(config.getMaxPoolSize()); executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); executor.setQueueCapacity(config.getQueueCapacity()); executor.setThreadNamePrefix("sync-"); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行 //对拒绝task的处理策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
3、spring bean的service层代码:
@Async public Future<BookResp> mockQueryDb(BookReqDTO req) { BookResp br = new BookResp(); br.setSn(req.getSn()); int mod = Integer.parseInt(req.getBookId()) % 3; br.setBookName("book" + mod); return new AsyncResult(br); }
4、spring的controller层代码:
@PostMapping(value = "listBook") @ApiOperation(value = "test", notes = "post") public List<BookResp> listBook(@RequestBody CompositeReq req) throws InterruptedException { List<BookReqDTO> list = req.getList(); //BlockingQueue<AggreTariffComputeResp> result = new LinkedBlockingQueue<>(list.size()); List<Future<BookResp>> futureResult = new ArrayList<>(list.size()); List<BookResp> result = new ArrayList<>(list.size()); for(BookReqDTO br : req.getList()) { bookService.mockQueryDb(br); Future<BookResp> computeAsync = bookService.mockQueryDb(br); futureResult.add(computeAsync); } while(!CollectionUtils.isEmpty(futureResult)) { Future<BookResp> future = futureResult.get(0); if(future.isDone()) { // 处理业务 try { result.add(future.get()); futureResult.remove(0); } catch (Exception e) { } } } return result; }
如果有多个web的线程进入,syncExceutor的线程池会被共用,当syncExceutor的线程不够用时,拒绝策略是使用调用者线程,也就阻塞web线程了。这个需要根据经验值配置线程池大小。