基于springboot线程池,来提高接口并发相关demo的性能压测和思考

背景:

    线上有个接口,需要循环调用其他系统的列表接口服务,之前是串行服务,考虑通过线程池来提高并行能力,业务代码进行了抽象,具体demo如下:


import com.facebook.presto.jdbc.internal.guava.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.vip.vman.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.common.errors.ApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Slf4j
@RestController
@RequestMapping(value = "/vman/thread")
public class ThreadController {

    @Autowired
    RedisService redisService;

    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-get-all-test-%d").build();
    private  final ExecutorService executorService =  new ThreadPoolExecutor(50,60, 180L, TimeUnit.SECONDS,new LinkedBlockingQueue(),namedThreadFactory);

    /**
     *  1、假设列表总共有100个任务 、每个业务处理时长 100ms,下面压测数据
     *  2、如果核心线程数是 20时,压测耗时  500ms
     *  3、如果核心线程数是 50时,压测耗时  200ms
     *  3、如果是走串行任务,发现固定耗时在  10000ms
     */
    @RequestMapping(value = "/test_thread", method = RequestMethod.GET)
    public void executeTask4(Integer id) throws InterruptedException {
        List<Integer> list = Lists.newLinkedList();
        for (int i = 0; i <100; i++) {
            list.add(i);
        }

        String str = redisService.getJedis().get("is_use_multi_thread");
        long currentTime = System.currentTimeMillis();
        if ("1".equals(str)) {
            multiThreadProcessSpaceSubjectGroup(list);
        }else {
            singleThreadProcessSpaceSubjectGroup(list);
        }

        log.info("整个任务运行时间:{}, is_use_multi_thread:{},", System.currentTimeMillis() - currentTime, str);
    }

    private void singleThreadProcessSpaceSubjectGroup(List<Integer> list) throws InterruptedException {
        for (Integer id : list) {
            log.info("执行接口任务任务:{}",id);
            Thread.sleep(100);
        }
    }


    private void multiThreadProcessSpaceSubjectGroup(List<Integer> list) {
        List<Future<?>> futures = new ArrayList<>();
        for (Integer id : list) {
            Callable<Void> crossSubjectCallable = () -> {
                log.info("执行接口任务任务:{}",id);
                if( id == 10) {
                    throw new ApiException("接口异常");
                }
                Thread.sleep(100);
                return null;
            };
            futures.add(executorService.submit(crossSubjectCallable));
        }

        for (Future<?> future : futures) {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // Handle exceptions
                log.info("获取接口异常:{}", e);
            }
        }
    }


}

压测的接口数据:

任务类型任务数核心线程数执行耗时
串行执行100串行可以理解单线程10000ms
线程池执行10020500ms
线程池执行10050200ms

通过改变线程池的核心线程数,发现接口性能提升明显,也参考了针对高并发场景相关线程,

业务场景线程池策略原因备注
高并发低耗时线程数可以设置少点如果设置线程数多,可能引起线程频繁切换,反而更耗时
低并发高耗时线程数可以设置多点线程切换不会影响长耗时任务
高并发高耗时

重点:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,可以使用线程池和CompletableFuture一起工作来提高应用程序的并发性能和响应性。 首先,你可以使用`ThreadPoolTaskExecutor`类来创建一个线程池。在Spring Boot中,你可以通过在应用程序的配置文件中添加以下属性来配置线程池: ```properties # 线程池配置 spring.task.execution.pool.core-size=10 spring.task.execution.pool.max-size=20 spring.task.execution.pool.queue-capacity=1000 spring.task.execution.pool.thread-name-prefix=my-thread- ``` 这个配置将创建一个具有10个核心线程和20个最大线程的线程池,以及一个容量为1000的工作队列。你可以根据你的需求进行调整。 接下来,你可以使用CompletableFuture来异步执行任务。CompletableFuture是一个Java 8引入的类,可以用于进行异步编程。你可以使用它的`supplyAsync()`方法来异步执行一个任务,并返回一个Future对象。 ```java CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 执行异步任务 return "任务结果"; }); ``` 你可以在CompletableFuture对象上调用`thenApply()`、`thenAccept()`或`thenRun()`等方法来处理异步任务的结果或执行其他操作。这些方法接收一个函数作为参数,用于处理任务的结果。 ```java future.thenApply(result -> { // 处理任务结果 return "处理后的结果"; }); ``` 在处理任务结果时,你可以利用线程池来执行一些耗时的操作,以避免阻塞主线程。你可以通过在CompletableFuture对象上调用`thenApplyAsync()`、`thenAcceptAsync()`或`thenRunAsync()`方法来异步执行操作。 ```java future.thenApplyAsync(result -> { // 异步处理任务结果 return "处理后的结果"; }, executor); ``` 在这里,`executor`是你之前配置的线程池对象。 通过将线程池和CompletableFuture结合起来使用,你可以实现更高效的并发处理和响应性能。记得根据实际需求调整线程池的配置,以避免资源浪费或线程饥饿等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值