线上有个接口,需要循环调用其他系统的列表接口服务,之前是串行服务,考虑通过线程池来提高并行能力,业务代码进行了抽象,具体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 |
线程池执行 | 100 | 20 | 500ms |
线程池执行 | 100 | 50 | 200ms |
通过改变线程池的核心线程数,发现接口性能提升明显,也参考了针对高并发场景相关线程,
业务场景 | 线程池策略 | 原因 | 备注 |
高并发低耗时 | 线程数可以设置少点 | 如果设置线程数多,可能引起线程频繁切换,反而更耗时 | |
低并发高耗时 | 线程数可以设置多点 | 线程切换不会影响长耗时任务 | |
高并发高耗时 |
重点: