CompletableFuture使用自定义线程池实现多任务结果聚合返回

为什么要使用自定义线程池?

默认线程池缺点

1、CompletableFuture默认使用的线程池是 ForkJoinPool.commonPool(),commonPool是当前 JVM(进程) 上的所有 CompletableFuture、并行 Stream 共享的,commonPool 的目标场景是非阻塞的 CPU 密集型任务,其线程数默认为 CPU 数量减1,所以对于我们用java常做的IO密集型任务,默认线程池是远远不够使用的
2、CompletableFuture是否使用默认线程池的依据,和机器的CPU核心数有关。当CPU核心数-1>1时,才会使用默认的线程池,否则将会为每个CompletableFuture的任务创建一个新线程去执行。

也就是说,CompletableFuture的默认线程池,只有在双核以上的机器内才会使用。在双核及以下的机器中,会为每个任务创建一个新线程,等于没有使用线程池,且有资源耗尽的风险。

因此建议,在使用CompletableFuture时,务必要自定义线程池。

创建自定义线程池

@Configuration
public class ThreadPoolConfig {
    //参数初始化
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    //核心线程数量大小
    private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT-1,4));
    //线程池最大容纳线程数
    private static final int maxPoolSize = CPU_COUNT * 2 + 1;
    //阻塞队列
    private static final int workQueue = 20;
    //线程空闲后的存活时长
    private static final int keepAliveTime = 30;

    @Bean("asyncTaskExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        //核心线程数
        threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
        //最大线程数
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        //等待队列
        threadPoolTaskExecutor.setQueueCapacity(workQueue);
        //线程前缀
        threadPoolTaskExecutor.setThreadNamePrefix("asyncTaskExecutor-");
        //线程池维护线程所允许的空闲时间,单位为秒
        threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveTime);
        // 线程池对拒绝任务(无线程可用)的处理策略
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        threadPoolTaskExecutor.initialize();

        return threadPoolTaskExecutor;
    }
}

var code = “44408f2e-720a-4910-9560-8379269da088”

在CompletableFuture中指定自定义线程池

@RestController
@RequestMapping("/task")
public class CompletableTaskController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    @Qualifier("asyncTaskExecutor")
    private Executor asyncTaskExecutor;

    @RequestMapping("testOrderTask")
    public String testOrderTask(){
        List<CompletableFuture<List<Integer>>> futureList = Lists.newArrayList();
        // 任务1,计算3秒
        CompletableFuture<List<Integer>> task1 = CompletableFuture.supplyAsync(() -> {
            sleepSeconds(3L);
            return Lists.newArrayList(1,2,3);
        }, asyncTaskExecutor);
        futureList.add(task1);

        // 任务2,计算2秒,得答案5
        CompletableFuture<List<Integer>> task2 = CompletableFuture.supplyAsync(() -> {
            sleepSeconds(1L);
            return Lists.newArrayList(4,5,6);
        }, asyncTaskExecutor);
        futureList.add(task2);

        // 任务3,计算3秒,得答案5
        CompletableFuture<List<Integer>> task3 = CompletableFuture.supplyAsync(() -> {
            sleepSeconds(2L);
            return Lists.newArrayList(7,8,9);
        }, asyncTaskExecutor);
        futureList.add(task3);
        // 写法1
        List<Integer> newList = futureList.stream().map(CompletableFuture::join).flatMap(List::stream).collect(Collectors.toList());
        return JSON.toJSONString(newList);
    }

    private void sleepSeconds(long seconds) {
        try {
            Thread.sleep(seconds * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试

运行以上程序,会 有以下输出:
1,2,3,4,5,6,7,8,9

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,可以通过以下步骤实现: 1. 首先创建一个RestHighLevelClient客户端对象,连接到Elasticsearch集群。 2. 构建一个SearchRequest对象,并设置其索引和查询条件。 3. 构建一个TermsAggregationBuilder对象,并设置其字段名。 4. 将TermsAggregationBuilder对象添加到SearchRequest对象中的AggregationBuilder中。 5. 执行查询,获取查询结果,并从中提取聚合结果。 以下是示例代码: ```java // 创建RestHighLevelClient客户端对象 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); // 构建SearchRequest对象 SearchRequest searchRequest = new SearchRequest("index_name"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder); // 构建TermsAggregationBuilder对象 TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("group_by_field").field("field_name"); // 将TermsAggregationBuilder对象添加到SearchRequest对象中 searchSourceBuilder.aggregation(aggregationBuilder); // 执行查询 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 获取聚合结果 Terms termsAggregation = searchResponse.getAggregations().get("group_by_field"); List<? extends Terms.Bucket> buckets = termsAggregation.getBuckets(); for (Terms.Bucket bucket : buckets) { System.out.println(bucket.getKeyAsString() + " " + bucket.getDocCount()); } // 关闭客户端连接 client.close(); ``` 其中,"index_name"为索引名,"field_name"为要进行分组聚合的字段名,"group_by_field"为聚合结果的名称。可以根据实际情况进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值