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线程了。这个需要根据经验值配置线程池大小。

 

posted on 2015-12-16 09:55  duanxz  阅读(2767)  评论(0编辑  收藏  举报