摘要:异步处理方式调用之后,不返回任何数据。在有返回值的异步调用中,异步处理抛出异常,会直接抛出异常,异步任务结束,原有处理结束执行。
1.使用背景
在项目中,当访问其他人的接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行,我们可以使用多线程来并行的处理任务,也可以使用spring提供的异步处理方式@Async。
2.异步处理方式调用之后,不返回任何数据。
调用之后,返回数据,通过Future来获取返回数据
3.@Async不返回数据使用@EnableAsync启用异步注解
@Configuration @EnableAsync @Slf4j public class AsyncConfig{ }
在异步处理的方法dealNoReturnTask上添加注解@Async
@Component @Slf4j public class AsyncTask { @Async public void dealNoReturnTask(){ log.info("Thread {} deal No Return Task start", Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } log.info("Thread {} deal No Return Task end at {}", Thread.currentThread().getName(), System.currentTimeMillis()); } }
Test测试类:
@SpringBootTest(classes = SpringbootApplication.class) @RunWith(SpringJUnit4ClassRunner.class) @Slf4j public class AsyncTest { @Autowired private AsyncTask asyncTask; @Test public void testDealNoReturnTask(){ asyncTask.dealNoReturnTask(); try { log.info("begin to deal other Task!"); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } }
日志打印结果为:
begin to deal other Task! AsyncExecutorThread-1 deal No Return Task start AsyncExecutorThread-1 deal No Return Task end at 1499751227034
从日志中我们可以看出,方法dealNoReturnTask()是异步执行完成的。
dealNoReturnTask()设置sleep 3s是为了模拟耗时任务
testDealNoReturnTask()设置sleep 10s是为了确认异步是否执行完成
异步调用返回数据,Future表示在未来某个点获取执行结果,返回数据类型可以自定义
@Async public FuturedealHaveReturnTask() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } JSONObject jsonObject = new JSONObject(); jsonObject.put("thread", Thread.currentThread().getName()); jsonObject.put("time", System.currentTimeMillis()); return new AsyncResult (jsonObject.toJSONString()); }
测试类用isCancelled判断异步任务是否取消,isDone判断任务是否执行结束
@Test public void testDealHaveReturnTask() throws Exception { Futurefuture = asyncTask.dealHaveReturnTask(); log.info("begin to deal other Task!"); while (true) { if(future.isCancelled()){ log.info("deal async task is Cancelled"); break; } if (future.isDone() ) { log.info("deal async task is Done"); log.info("return result is " + future.get()); break; } log.info("wait async task to end ..."); Thread.sleep(1000); } }
日志打印如下,我们可以看出任务一直在等待异步任务执行完毕,用future.get()来获取异步任务的返回结果
begin to deal other Task! wait async task to end ... wait async task to end ... wait async task to end ... wait async task to end ... deal async task is Done return result is {"thread":"AsyncExecutorThread-1","time":1499752617330}4.异常处理
我们可以实现AsyncConfigurer接口,也可以继承AsyncConfigurerSupport类来实现
在方法getAsyncExecutor()中创建线程池的时候,必须使用 executor.initialize(),
不然在调用时会报线程池未初始化的异常。
如果使用threadPoolTaskExecutor()来定义bean,则不需要初始化
@Configuration @EnableAsync @Slf4j public class AsyncConfig implements AsyncConfigurer { // @Bean // public ThreadPoolTaskExecutor threadPoolTaskExecutor(){ // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // executor.setCorePoolSize(10); // executor.setMaxPoolSize(100); // executor.setQueueCapacity(100); // return executor; // } @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(100); executor.setQueueCapacity(100); executor.setThreadNamePrefix("AsyncExecutorThread-"); executor.initialize(); //如果不初始化,导致找到不到执行器 return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncExceptionHandler(); } }
异步异常处理类:
@Slf4j public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { log.info("Async method: {} has uncaught exception,params:{}", method.getName(), JSON.toJSONString(params)); if (ex instanceof AsyncException) { AsyncException asyncException = (AsyncException) ex; log.info("asyncException:{}",asyncException.getErrorMessage()); } log.info("Exception :"); ex.printStackTrace(); } }
异步处理异常类:
@Data @AllArgsConstructor public class AsyncException extends Exception { private int code; private String errorMessage; }
在无返回值的异步调用中,异步处理抛出异常,AsyncExceptionHandler的handleUncaughtException()会捕获指定异常,原有任务还会继续运行,直到结束。
在有返回值的异步调用中,异步处理抛出异常,会直接抛出异常,异步任务结束,原有处理结束执行。
大家可以关注我的公众号:不知风在何处,相互沟通,共同进步。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67362.html
摘要:异步程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序当一个异步过程调用发出后,调用者不能立刻得到结果。 同步 程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。 异步 程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序,当一个异步过程调用发出后,调用者不能立刻得到结果。 ...
摘要:定义异步方法,使用来返回异步调用的结果开始做任务一完成任务一,当前线程,耗时毫秒任务一完成开始做任务二完成任务二,当前线程,耗时毫秒任务二完成开始做任务三完成任务三,当前线程,耗时毫秒任务三完成调用执行异步回调异步回调结束调用结果开 定义异步方法,使用Future来返回异步调用的结果 @Async public Future firstTask() throws Int...
摘要:对多线程的支持详解这两天看阿里的开发手册,到多线程的时候说永远不要用这种方式来使用多线程。在使用线程池的大多数情况下都是异步非阻塞的。二配置类配置类代码如下下午解读利用来开启对于异步任务的支持配置类实现接口,返回一个线程池对象。 Springboot对多线程的支持详解 这两天看阿里的JAVA开发手册,到多线程的时候说永远不要用 new Thread()这种方式来使用多线程。确实是这样的...
摘要:最开始是使用的正常的普通方式去写入,但是量太大了,所以就尝试使用多线程来写入。下面我们就来介绍一下怎么使用多线程进行导入。配置线程池我们需要创建一个类来设置线程池的各种配置。它可以使主线程一直等到所有的子线程执行完之后再执行。 前言: 最近在工作中需要将一大批数据导入到数据库中,因为种种原因这些数据不能使用同步数据的方式来进行复制,而是提供了一批文本,文本里面有很多行url地址,需要的...
阅读 3411·2023-04-25 23:25
阅读 2038·2021-11-12 10:36
阅读 2797·2019-08-30 12:47
阅读 2017·2019-08-29 18:45
阅读 399·2019-08-29 17:28
阅读 1756·2019-08-29 17:15
阅读 1671·2019-08-29 16:05
阅读 1378·2019-08-29 14:17