Spring Boot 异步

当某个请求执行非常耗时,当有大量访问该请求的时候,再访问请求其他服务时,会出现没有连接使用的情况。造成这种现象的主要原因是,容器中线程的数量是一定的,如果当所有线程都正在用来处理请求服务的时候,再有请求进来就没有多余的连接可用,只能拒绝连接。

SpringBoot异步机制可以使请求到了controller的时候,容器中的线程直接返回,同时使用系统内部的线程来执行耗时的服务,处理结束后果再将请求返回给客户端。

Servlet 3.0 新增了请求的异步处理,Spring 3.2 也在此基础上做了封装处理。
Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。

在 Spring Boot 框架中,可以在配置类中添加@EnableAsync开始对异步任务的支持,并将相应的方法使用@Async注解来声明为一个异步任务。 

对于@Transactional、@Async等注解,Spring扫描到具有这些注解方法的类时,生成一个代理类,由代理类去执行,所以异步方法必须在类外部调用,并且@Async所修饰的不能是static方法。获取得到执行结果则可设置异步函数返回类型为Future

@Component  
public class MyAsyncTask {  
    @Async  
    public Future<String> task1() throws InterruptedException{  
        return new AsyncResult<String>("task1执行完毕");  
    }  

Controller的方法可以很快返回一个java.util.concurrent.Callable或DeferredResult,同时Servlet容器的主线程退出和释放,这并不意味着客户端收到了一个响应。

//Callable
@Controller
public class DefaultController {
    @RequestMapping("/async/test")
    @ResponseBody
    public Callable<String> callable() {
        //调用后生成一个非web线程来执行部分代码。
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3 * 1000L);
                return "finish" + System.currentTimeMillis();
            }
        };
    }
}

//DeferredResult
@RestController  
public class AsyncDeferredController {  
    private final TaskService taskService;  
      
    @Autowired  
    public AsyncDeferredController(TaskService taskService) {  
        this.taskService = taskService;  
    }  
      
    @RequestMapping(value = "/deferred", method = RequestMethod.GET, produces = "text/html")  
    public DeferredResult<String> executeSlowTask() {  
        DeferredResult<String> deferredResult = new DeferredResult<>();  
        CompletableFuture.supplyAsync(taskService::execute).whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));  

        return deferredResult;  
    }  
}  

Callable的其它示例:

public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable = new CallableImpl("my callable test!");
        FutureTask<String> task = new FutureTask<>(callable);
        new Thread(task).start();
        //调用get()会阻塞主线程。
        String result = task.get();
    }

Callable和DeferredResult的区别:

Callable和DeferredResult效果都是释放容器线程,在另一个线程中运行长时间的任务。

不同的是谁管理执行任务的线程:

  • Callable在执行线程完毕时返回。
  • Deferredresult是通过设置返回对象值返回,可以在任何地方控制返回。


定时任务


1.在程序入口类上添加类注解 @EnableScheduling 来启用计划任务
2.在定时任务的类上加上类注解 @Component,在具体的定时任务方法上加上注解 @Scheduled 启动该定时任务。

@Scheduled(initialDelay=10000, fixedDelay=10000) //10 seconds, or use cron express

默认所有的@Scheduled都是串行执行的,并行需要继承SchedulingConfigurer类并重写其方法,实现并行任务。

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值