java asyncexec_Spring boot使用@Async实现异步调用

大多数情况下都是通过同步的方式来实现交互处理的

但是在处理与第三方系统交互的时候,经常会响应迟缓

可以使用@Async实现异步调用

1.使用@Async

使用步骤:

使用@EnableAsync开启异步;

定义Spring组件,使用@Component和@Async

(1)添加依赖

org.springframework.boot

spring-boot-starter-web

(2)修改启动类

添加@EnableAsync开启异步

packagecom.abc.xyz;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication

@EnableAsyncpublic classXyzApplication {public static voidmain(String[] args) {

SpringApplication.run(XyzApplication.class, args);

}

}

(3)定义Spring 组件

packagecom.abc.xyz;importorg.springframework.scheduling.annotation.Async;importorg.springframework.scheduling.annotation.AsyncResult;importorg.springframework.stereotype.Component;importjava.util.concurrent.Future;

@Componentpublic classMyTask {

@Asyncpublic voidtask1() {long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task1任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task1任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());

}

@Asyncpublic Futuretask2() {long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task2任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task2任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());return new AsyncResult<>("success");

}

}

(4)测试

packagecom.abc.xyz.controller;importcom.abc.xyz.MyTask;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;

@RestControllerpublic classHelloController {

@AutowiredprivateMyTask myTask;

@RequestMapping("/test")publicString test(){

System.out.println("task before");

myTask.task1();

System.out.println("task after");return "OK";

}

}

启动项目

浏览器打开http://localhost:8080/test

输出OK

控制台输出

task before

task after

task1任务开始, timestamp=1576415623066, threadId=51, threadName=task-1

task1任务结束, timestamp=1576415626067, threadId=51, threadName=task-1

从输出看出,任务是异步执行的

2.带有返回值的异步

返回值Future

添加带返回值的task2()

packagecom.abc.xyz;importorg.springframework.scheduling.annotation.Async;importorg.springframework.scheduling.annotation.AsyncResult;importorg.springframework.stereotype.Component;importjava.util.concurrent.Future;

@Componentpublic classMyTask {

@Asyncpublic voidtask1() {long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task1任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task1任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());

}

@Asyncpublic Futuretask2() {long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task2任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task2任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());return new AsyncResult<>("success");

}

}

测试方法

packagecom.abc.xyz.controller;importcom.abc.xyz.MyTask;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.concurrent.Future;

@RestControllerpublic classHelloController {

@AutowiredprivateMyTask myTask;

@RequestMapping("/test")publicString test(){try{long start =System.currentTimeMillis();

System.out.println("task before");

Future rs =myTask.task2();

System.out.println(rs.get());

myTask.task1();

System.out.println("task after");

System.out.println("执行时间"+(System.currentTimeMillis()-start));

}catch(Exception e){

e.printStackTrace();

}return "OK";

}

}

启动项目,控制台输出

task before

task2任务开始, timestamp=1576416889468, threadId=51, threadName=task-1

task2任务结束, timestamp=1576416892469, threadId=51, threadName=task-1

success

task after

执行时间3016

task1任务开始, timestamp=1576416892474, threadId=52, threadName=task-2

task1任务结束, timestamp=1576416895474, threadId=52, threadName=task-2

说明:

@Async注解声明的方法,返回类型要么为void,要么为Future

方法是异步调用的,无法立即返回结果,如果声明为其它返回类型,获取到的是null

声明为Future,则可以获取到任务的执行结果,结果用Future的get()方法获取

3.异常处理

(1)带返回值的异常处理

带Future类型的返回值时,在调Future的get()方法获取任务的执行结果时抛出的异常

修改task2

@Asyncpublic Future task2() throwsException{long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task2任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task2任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());return new AsyncResult<>("success");

}

(2)不带返回值的异常处理

不带返回值的异常无法被调用者捕获,可以实现AsyncUncaughtExceptionHandler来处理

添加 MyAsyncUncaughtExceptionHandler 实现 AsyncUncaughtExceptionHandler

packagecom.tydt.bim.common;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;importjava.lang.reflect.Method;public class MyAsyncUncaughtExceptionHandler implementsAsyncUncaughtExceptionHandler {private final Logger logger = LoggerFactory.getLogger(MyAsyncUncaughtExceptionHandler.class);

@Overridepublic voidhandleUncaughtException(Throwable ex, Method method, Object... params) {

logger.error("Exception occurs in async method:",ex.getMessage());

}

}

添加 AsyncConfig 实现 AsyncConfigurer 并覆盖 AsyncUncaughtExceptionHandler 方法

packagecom.abc.xyz;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.AsyncConfigurer;

@Configurationpublic class AsyncConfig implementsAsyncConfigurer {

@OverridepublicAsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return newMyAsyncUncaughtExceptionHandler();

}

}

4.线程调度配置

Spring boot 默认配置的线程池是ThreadPoolTaskExecutor

修改配置文件

spring.task.execution.pool.core-size=8spring.task.execution.pool.max-size=16spring.task.execution.pool.queue-capacity=100spring.task.execution.pool.keep-alive=10s

spring.task.execution.pool.core-size # 核心线程数,默认为8

spring.task.execution.pool.max-size # 最大线程数,默认为无限大

spring.task.execution.pool.queue-capacity # 队列容量,默认为无限大

spring.task.execution.pool.keep-alive # 空闲的线程可以保留多少秒,默认为60。如果超过这个时间没有任务调度,则线程会被回收

5.自定义线程调度器

通过实现AsyncConfigurer接口来定义自己的线程调度器

修改 AsyncConfig

packagecom.abc.xyz;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.AsyncConfigurer;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importjava.util.concurrent.Executor;

@Configurationpublic class AsyncConfig implementsAsyncConfigurer {

@OverridepublicExecutor getAsyncExecutor() {

ThreadPoolTaskExecutor executor= newThreadPoolTaskExecutor();

executor.setCorePoolSize(10);

executor.setMaxPoolSize(20);

executor.setQueueCapacity(100);

executor.setThreadNamePrefix("my-executor-");

executor.initialize();returnexecutor;

}

@OverridepublicAsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return newMyAsyncUncaughtExceptionHandler();

}

}

重新启动,控制台输出

task before

2019-12-15 22:00:44.725 INFO 9204 --- [nio-8080-exec-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService

task2任务开始, timestamp=1576418444734, threadId=51, threadName=my-executor-1

task2任务结束, timestamp=1576418447736, threadId=51, threadName=my-executor-1

success

task after

执行时间3017

task1任务开始, timestamp=1576418447740, threadId=52, threadName=my-executor-2

task1任务结束, timestamp=1576418450740, threadId=52, threadName=my-executor-2

说明:

线程池的前缀改成了my-executor-

输出o.s.s.concurrent.ThreadPoolTaskExecutor,是因为没有指定异步执行的executor,在第一次执行的时候会进行初始化

6.多线程池

让线程池只做一件事,防止多个共用线程池出线抢占溢出情况

修改 AsyncConfig,添加task1Executor,task2Executor

packagecom.abc.xyz;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.AsyncConfigurer;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importjava.util.concurrent.Executor;

@Configurationpublic class AsyncConfig implementsAsyncConfigurer {

@BeanpublicExecutor task1Executor() {

ThreadPoolTaskExecutor executor= newThreadPoolTaskExecutor();

executor.setCorePoolSize(2);

executor.setMaxPoolSize(3);

executor.setQueueCapacity(10);

executor.setThreadNamePrefix("task1-executor-");

executor.initialize();returnexecutor;

}

@BeanpublicExecutor task2Executor() {

ThreadPoolTaskExecutor executor= newThreadPoolTaskExecutor();

executor.setCorePoolSize(2);

executor.setMaxPoolSize(3);

executor.setQueueCapacity(10);

executor.setThreadNamePrefix("task2-executor-");

executor.initialize();returnexecutor;

}

@OverridepublicExecutor getAsyncExecutor() {

ThreadPoolTaskExecutor executor= newThreadPoolTaskExecutor();

executor.setCorePoolSize(1);

executor.setMaxPoolSize(2);

executor.setQueueCapacity(10);

executor.setThreadNamePrefix("my-executor-");

executor.initialize();returnexecutor;

}

@OverridepublicAsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return newMyAsyncUncaughtExceptionHandler();

}

}

使用线程池

packagecom.abc.xyz;importorg.springframework.scheduling.annotation.Async;importorg.springframework.scheduling.annotation.AsyncResult;importorg.springframework.stereotype.Component;importjava.util.concurrent.Future;

@Componentpublic classMyTask {

@Async("task1Executor")public voidtask1() {long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task1任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task1任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());

}

@Async("task2Executor")public Future task2() throwsException{long timestamp =System.currentTimeMillis();

Thread thread=Thread.currentThread();

System.out.println("task2任务开始, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());try{

Thread.sleep(3000);

}catch(Exception e) {

e.printStackTrace();

}

timestamp=System.currentTimeMillis();

System.out.println("task2任务结束, timestamp=" + timestamp + ", threadId=" + thread.getId() + ", threadName=" +thread.getName());return new AsyncResult<>("success");

}

}

重新启动,控制台输出

task before

task2任务开始, timestamp=1576419065314, threadId=52, threadName=task2-executor-1

task2任务结束, timestamp=1576419068315, threadId=52, threadName=task2-executor-1

success

task after

执行时间3052

task1任务开始, timestamp=1576419068354, threadId=53, threadName=task1-executor-1

task1任务结束, timestamp=1576419071356, threadId=53, threadName=task1-executor-1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值