springboot项目中多线程应用,异步处理,异步调用

springboot项目中多线程应用,异步处理,异步调用

多线程的应用

线程池的应用

异步处理

异步调用

随着开发经验的积累,我们逐渐都了解到了项目中需要多线程的应用或者线程池的应用,有一些耗时的业务需要我们去进行异步调用,特别是针对于一些其他部门所提供的接口,因此码下这篇博客,希望对大家有用!

配置一个线程池

@EnableAsync
@Configuration
@Slf4j
public class ThreadPoolConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    // 当池子大小小于corePoolSize,就新建线程,并处理请求
    // 当池子大小等于corePoolSize,把请求放入workQueue(QueueCapacity)中,池子里的空闲线程就去workQueue中取任务并处理
    // 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
    // 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁
    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(30);
        executor.setThreadNamePrefix("async-");
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

}

定义两个额外的比较耗时的测试接口

@Slf4j
@RestController
@RequestMapping(value = "/test")
public class TestController {
  
    @GetMapping(value = "/hello1")
    public JSONObject hello1 (String name) throws InterruptedException {
        log.info("this is hello1 ---> sleep(5000) begin " + new Date());
        Thread.sleep(5000);
        log.info("this is hello1 ---> sleep(5000) end   " + new Date());
        JSONObject res = new JSONObject();
        res.put("name", "hello1-" + name);
        return res;
    }

    @GetMapping(value = "/hello2")
    public JSONObject hello2 (String name) throws InterruptedException {
        log.info("this is hello2 ---> sleep(8000) begin " + new Date());
        Thread.sleep(8000);
        log.info("this is hello2 ---> sleep(8000) end   " + new Date());
        JSONObject res = new JSONObject();
        res.put("name", "hello2-" + name);
        return res;
    }
  
}

定义多线程调用的业务类

@Service
@Slf4j
public class OtherService {

    @Autowired
    private RestTemplate restTemplate;

    @Async("asyncServiceExecutor")
    public CompletableFuture<JSONObject> invokeHello1(String name){
        String url = "http://localhost:8080/test/hello1?name=" + name;
        log.info("多线程开始执行{}, threadId:{}, threadName:{}", url, Thread.currentThread().getId(), Thread.currentThread().getName());
        ResponseEntity<JSONObject> responseEntity = restTemplate.getForEntity(url, JSONObject.class);
        JSONObject jsonRes = responseEntity.getBody();
        log.info("多线程执行完毕{}, 响应Res:{}, threadId:{}, threadName:{}", url, jsonRes, Thread.currentThread().getId(), Thread.currentThread().getName());
        return CompletableFuture.completedFuture(jsonRes);
    }

    @Async("asyncServiceExecutor")
    public CompletableFuture<JSONObject> invokeHello2(String name){
        String url = "http://localhost:8080/test/hello2?name=" + name;
        log.info("多线程开始执行{}, threadId:{}, threadName:{}", url, Thread.currentThread().getId(), Thread.currentThread().getName());
        ResponseEntity<JSONObject> responseEntity = restTemplate.getForEntity(url, JSONObject.class);
        JSONObject jsonRes = responseEntity.getBody();
        log.info("多线程执行完毕{}, 响应Res:{}, threadId:{}, threadName:{}", url, jsonRes, Thread.currentThread().getId(), Thread.currentThread().getName());
        return CompletableFuture.completedFuture(jsonRes);
    }

}

定义要使用多线程的接口

@Slf4j
@RestController
@RequestMapping(value = "/test")
public class TestController {
  
    @Autowired
    private Demo3Service demo3Service;

    @GetMapping(value = "/testHello")
    public JSONObject testHello (String name) throws ExecutionException, InterruptedException {
        return demo3Service.testHello(name);
    }
  
}

定义要使用多线程的servcie

@Service
@Slf4j
public class Demo3Service {

    @Autowired
    private OtherService otherService;

    public JSONObject testHello (String name) throws ExecutionException, InterruptedException {
        log.info("this is demo3Service.testHello({}), begin -> {}", name, new Date());
        // 此处hello1和hello2均为异步调用
        CompletableFuture<JSONObject> hello1Future = otherService.invokeHello1(name);
        CompletableFuture<JSONObject> hello2Future = otherService.invokeHello2(name);
        // 这里可以处理其他的业务逻辑
        log.info("async invoke doing...");
        // 开始处理hello1和hello2的接口相应
        CompletableFuture.allOf(hello1Future, hello2Future).join();
        JSONObject hello1Res = hello1Future.get();
        JSONObject hello2Res = hello2Future.get();
        log.info("this is demo3Service.testHello({}), end -> {}", name, new Date());
        JSONObject jsonRes = new JSONObject();
        jsonRes.put("hello1", hello1Res.get("name"));
        jsonRes.put("hello2", hello2Res.get("name"));
        return jsonRes;
    }
    
}

最后,让我们一起来测试一下 http://localhost:8080/test/testHello?name=zhangsan这个接口

一起来看一下控制台输出的日志

this is demo3Service.testHello(zhangsan), begin -> Mon Apr 11 22:59:13 CST 2022
async invoke doing...
多线程开始执行http://localhost:8080/test/hello1?name=zhangsan, threadId:43, threadName:async-1
多线程开始执行http://localhost:8080/test/hello2?name=zhangsan, threadId:44, threadName:async-2
this is hello2 ---> sleep(8000) begin Mon Apr 11 22:59:13 CST 2022
this is hello1 ---> sleep(5000) begin Mon Apr 11 22:59:13 CST 2022
this is hello1 ---> sleep(5000) end   Mon Apr 11 22:59:18 CST 2022
多线程执行完毕http://localhost:8080/test/hello1?name=zhangsan, 响应Res:{"name":"hello1-zhangsan"}, threadId:43, threadName:async-1
this is hello2 ---> sleep(8000) end   Mon Apr 11 22:59:21 CST 2022
多线程执行完毕http://localhost:8080/test/hello2?name=zhangsan, 响应Res:{"name":"hello2-zhangsan"}, threadId:44, threadName:async-2
this is demo3Service.testHello(zhangsan), end -> Mon Apr 11 22:59:21 CST 2022

OK,这就是多线程/线程池的一个基本使用了,希望能帮到大家

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

难过的风景

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值