java 异步处理接口_调用接口,异步处理业务

调用接口时,如果后台需要处理的时间过长,需要采取异步处理,先把结果返回给前台。

1、原生的

接口定义:

@RequestMapping(value="/test")publicObject test(){

MyExecutor myExecutor= newMyExecutor();try{

myExecutor.work();

}catch(Exception e) {

System.out.println("myExecutor.work()"+e.getMessage());

}

System.out.println("返回结果: "+newDate());return "成功";

}

业务执行:

importjava.util.Date;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;public classMyExecutor {private ExecutorService executor =Executors.newCachedThreadPool() ;public void work() throwsException {

executor.submit(newRunnable(){public voidrun() {try{

System.out.println("开始处理业务。。。 "+newDate());

Thread.sleep(5000);

System.out.println("业务结束。。。 "+newDate());

}catch(Exception e) {

System.out.println(e.getMessage());

}

}

});

}

}

控制台输出:

返回结果: Sat Jul 27 09:28:33 GMT+08:00 2019开始处理业务。。。 Sat Jul27 09:28:33 GMT+08:00 2019业务结束。。。 Sat Jul27 09:28:38 GMT+08:00 2019

2、在springboot  中使用

controller层

@RequestMapping(value="/async2")publicObject testAsync2(){System.out.println(1111);

userService.testAsync();

System.out.println(12);return "asdfas";

}

异步方法加注解    @Async (org.springframework.scheduling.annotation.Async;)

@Override

@Asyncpublic voidtestAsync() {

System.out.println("开始异步处理业务。。");try{

Thread.sleep(5000);

System.out.println("结束。。。。。");

}catch(InterruptedException e) {

e.printStackTrace();

}

}

启动类加注解  @EnableAsync  开启异步支持

扩展:

异步方法有返回值

@Asyncpublic FutureasyncMethodWithReturnType() {

System.out.println("Execute method asynchronously - "+Thread.currentThread().getName());try{

Thread.sleep(5000);return new AsyncResult("hello world !!!!");

}catch(InterruptedException e) {//}return null;

}

异步操作的执行器

默认情况下,Spring 使用SimpleAsyncTaskExecutor去执行这些异步方法(此执行器没有限制线程数)。此默认值可以从两个层级进行覆盖:

1. 方法级别覆盖

@Async("threadPoolTaskExecutor")public voidasyncMethodWithConfiguredExecutor() {

System.out.println("Execute method with configured executor - "+Thread.currentThread().getName());

}

2. 应用级别覆盖

配置类应该实现AsyncConfigurer接口——这意味着它拥有getAsyncExecutor()方法的实现。在这里,我们将返回整个应用程序的执行器——这现在成为运行带有@Async注释的方法的默认执行器:(异步中的线程名称-- ThreadPoolTaskExecutor-1 ,与所使用的执行相关)

importjava.util.concurrent.Executor;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;importorg.springframework.scheduling.annotation.AsyncConfigurer;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration

@EnableAsyncpublic class SpringAsyncConfig implementsAsyncConfigurer{

@OverridepublicExecutor getAsyncExecutor() {

ThreadPoolTaskExecutor executor= newThreadPoolTaskExecutor();

executor.initialize();

executor.setCorePoolSize(5);

executor.setMaxPoolSize(10);

executor.setQueueCapacity(25);returnexecutor;

}

@OverridepublicAsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return newCustomAsyncExceptionHandler();

}

}

CustomAsyncExceptionHandler 是一个自定义的异常捕捉,当方法返回值是Future的时候,异常捕获是没问题的 - Future.get()方法会抛出异常。但是,如果返回类型是Void,那么异常在当前线程就捕获不到。因此,我们需要添加额外的配置来处理异常。

通过实现AsyncUncaughtExceptionHandler接口创建一个定制的async异常处理程序。handleUncaughtException()方法在存在任何未捕获的异步异常时调用:

importjava.lang.reflect.Method;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;public class CustomAsyncExceptionHandler implementsAsyncUncaughtExceptionHandler {

@Overridepublic voidhandleUncaughtException(

Throwable throwable, Method method, Object... obj) {

System.out.println("Exception message - " +throwable.getMessage());

System.out.println("Method name - " +method.getName());for(Object param : obj) {

System.out.println("Parameter value - " +param);

}

}

}

3、spring MVC 中使用

需要加配置

相关的配置:

配置:

executor:指定一个缺省的executor给@Async使用。

例子:

配置参数:

id:当配置多个executor时,被@Async("id")指定使用;也被作为线程名的前缀。

pool-size:

core size:最小的线程数,缺省:1

max size:最大的线程数,缺省:Integer.MAX_VALUE

queue-capacity:当最小的线程数已经被占用满后,新的任务会被放进queue里面,当这个queue的capacity也被占满之后,pool里面会创建新线程处理这个任务,直到总线程数达到了max size,这时系统会拒绝这个任务并抛出TaskRejectedException异常(缺省配置的情况下,可以通过rejection-policy来决定如何处理这种情况)。缺省值为:Integer.MAX_VALUE

keep-alive:超过core size的那些线程,任务完成后,再经过这个时长(秒)会被结束掉

rejection-policy:当pool已经达到max size的时候,如何处理新任务

ABORT(缺省):抛出TaskRejectedException异常,然后不执行

DISCARD:不执行,也不抛出异常

DISCARD_OLDEST:丢弃queue中最旧的那个任务

CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

配置例子:

实例:

@Override

@Async("logExecutor") //如果不指定名字,会使用缺省的“asyncExecutor”

public void saveUserOpLog(TabUserOpLog tabUserOpLog) {

userOpLogDAO.insertTabUserOpLog(tabUserOpLog);

}

java 异步处理接口_调用接口,异步处理业务_第1张图片

线程的优先级和类型:

优先级:NORM_PRIORITY

类型:非守护线程

用户线程(User Thread):JVM会等待所有的用户线程结束后才退出;当系统中没有用户线程了,JVM也就退出了

守护线程(Daemon Thread):一般是为其他线程提供服务的线程,比如GC垃圾回收器;JVM退出时,不会管守护线程是否存在,而是直接退出

所以,对于文件、数据库的操作,不适宜使用守护线程,不然可能会丢失数据!

Web应用停止时,Spring容器会被关闭,调用者如果是Spring bean,就会停止生成新任务。然而,线程池中已经在运行的任务,由于缺省是用户线程,所以JVM会等待它们结束后才退出。

附:Java编程方式的配置方法:

@Configuration

@EnableAsyncpublic classSpringConfig {/**Set the ThreadPoolExecutor's core pool size.*/

private int corePoolSize = 10;/**Set the ThreadPoolExecutor's maximum pool size.*/

private int maxPoolSize = 200;/**Set the capacity for the ThreadPoolExecutor's BlockingQueue.*/

private int queueCapacity = 10;private String ThreadNamePrefix = "MyLogExecutor-";

@BeanpublicExecutor logExecutor() {

ThreadPoolTaskExecutor executor= newThreadPoolTaskExecutor();

executor.setCorePoolSize(corePoolSize);

executor.setMaxPoolSize(maxPoolSize);

executor.setQueueCapacity(queueCapacity);

executor.setThreadNamePrefix(ThreadNamePrefix);//rejection-policy:当pool已经达到max size的时候,如何处理新任务//CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());

executor.initialize();returnexecutor;

}

}

SimpleAsyncTaskExecutor

你可能感兴趣的:(java,异步处理接口)