程序员社区

Spring Boot 异步处理任务

项目场景:

       现在需要上传一个Excel表格,数据量几万条,而且,上传解析后还需要进行计算,然后插入数据库。

分析:

       上传和解析,都很简单,但是,这里如果使用同步方式,那么:上传–>解析–>运算–>插入数据库;这个过程,前台的页面都是等待状态的,用户会以为页面卡死了。所以,这里需要做异步处理:

1.上传–>返回正在解析的标志;

2.解析–>运算–>插入数据库;

此时,当用户上传完文件后,页面立马跳转,解析,运算等工作,继续在后台进行,而用户可以不用等待。

Spring Boot 异步任务处理方式

Tip:
        推荐使用 【方式二】:Spring Boot 基于注解方式开启异步任务处理,可以省去编写多线程的繁琐任务,并且只需要@EnableAsync 和 @Async 两个注解即可解决问题,so 完美

1.同步方式

  controller

 /** * 同步处理 * @return */
@RequestMapping(value = "test2",method = RequestMethod.GET)
public String test2(){
   
    loginService.getTest2();
    logger.info(Thread.currentThread().getName()+"==========主线程名");
    return "同步,正在解析......";
}

  serviceImpl

 /**同步方法*/
@Override
public void getTest2(){
   
    Building building = new Building();
    synchronized (building){
   
        try {
   
            for (int i = 1;i <= 100;i++){
   
                logger.info(Thread.currentThread().getName()+"----------同步:>"+i);
                building.wait(200);
            }
        }catch (Exception ex){
   
            ex.printStackTrace();
        }
    }
}

       这种同步的方式处理,会发现,当这100次循环完成后,页面才会返回 :同步,正在解析…。当后台在循环处理时,前台的页面始终处于等待状态。可以发现,使用都是一个线程在处理:
在这里插入图片描述

2.异步任务【方式一】

使用线程池,创建新的线程去处理,如下:

  controller

/** * 异步处理1:线程池,创建新线程处理 * @return */
@RequestMapping(value = "test3",method = RequestMethod.GET)
public String test3(){
   
    ExecutorService service = Executors.newFixedThreadPool(5);
    RunnableTask1 task1 = new RunnableTask1();
    service.execute(task1);
    logger.info("=========》当前线程名:"+Thread.currentThread().getName());
    return "异步,正在解析......";
}

  线程任务

public class RunnableTask1 implements Runnable{
   
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void run(){
   
        Building building = new Building();
        synchronized (building){
   
            try {
   
                for (int i = 1;i <= 100;i++){
   
                    System.out.println(Thread.currentThread().getName()+"----------异步:>"+i);
                    building.wait(200);
                }
            }catch (Exception ex){
   
                ex.printStackTrace();
            }
        }
    }
}

       我们看控制台会发现:主线程和处理任务的线程,不是一个线程;即:当页面请求后,主线程会返回我们想要返回的标识,这里返回的是一个字符串:异步,正在解析…,而线程池新开了一个线程,在后台处理业务逻辑。所以,此时访问接口后,会立马返回,页面不用等待,处理逻辑在后台默默进行。控制台如下:
在这里插入图片描述

3.(推荐)异步任务【方式二】

       这种方式,是Spring Boot自身的一种异步方式,使用注解实现,非常方便。我们在想要异步执行的方法上加上@Async注解,在项目启动类上加上@EnableAsync注解即可。注意:这里的异步方法,只能在自身之外调用,在本类调用是无效的。

 项目启动类 SpringbootApplication

@EnableAsync  //开启异步注解功能
@SpringBootApplication
public class SpringbootApplication {
   
    public static void main(String[] args) {
   
        SpringApplication.run(SpringbootApplication .class, args);
    }
}

 controller

@RestController
@RequestMapping("tmall")
public class LoginController {
   
    private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private LoginService loginService;
    /** * 异步处理2:使用springBoot自带async注解 */
    @RequestMapping(value = "test1",method = RequestMethod.GET)
    public String test1(){
   
        loginService.getTest1();
        logger.info("============>"+Thread.currentThread().getName());
        return "异步,正在解析......";
    }
}

 serviceImpl

/**异步方法 * 有@Async注解的方法,默认就是异步执行的,会在默认的线程池中执行,但是此方法不能在本类调用;启动类需添加直接开启异步执行@EnableAsync。 * */
@Async
@Override
public String getTest1(){
   
    Building building = new Building();
    synchronized (building){
   
        try {
   
            for (int i = 1;i <= 100;i++){
   
                logger.info(Thread.currentThread().getName()+"----------异步:>"+i);
                building.wait(200);
            }
            return "执行异步任务完毕";
        }catch (Exception ex){
   
            ex.printStackTrace();
        }
    }
    return Thread.currentThread().getName()+"执行完毕";
}

       看控制台,会发现,页面发出请求后,主线程会返回,而内置的线程池会新开线程,在后台执行任务。此时页面不用等待,可以继续其他操作。
在这里插入图片描述
       可以看到,很多情况下,异步处理,是一种很常见,而且很高效的方式。相比较需要使用多线程解决异步,我们肯定更喜欢使用 Spring Boo t自带的注解方式,只用两个注解即可了


本文为转载文章,在原文基础上有所修改,仅用作学习记录

如果本文对你有所帮助,那就给我点个赞呗

End

赞(0) 打赏
未经允许不得转载:IDEA激活码 » Spring Boot 异步处理任务

一个分享Java & Python知识的社区