@Async的使用

  • Post author:
  • Post category:其他



Spring项目中

:控制器上添加注解@EnableAsync 要异步执行的方法上添加注解@Async

controller

package com.async.demo.controller;

import com.async.demo.service.AsyncDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@EnableAsync
@RestController("asyncDemo")
public class AsyncDemoController {

    @Autowired
    public AsyncDemoService asyncDemoService;

    @GetMapping("/takeTea")
    public String takeTea(double cost){
        System.out.println("开始调用喝茶...线程名:"+Thread.currentThread().getName());
        asyncDemoService.drinkTea(cost);
        return "ok";
    }

}

service

package com.async.demo.service;

public interface AsyncDemoService {
    void drinkTea(double cost);
}

impl

package com.async.demo.service.impl;

import com.async.demo.service.AsyncDemoService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class AsynDemoServiceImpl implements AsyncDemoService {
    @Async
    @Override
    public void drinkTea(double cost) {
        System.out.println("喝茶...线程名:"+Thread.currentThread().getName());
        System.out.println("it takes "+cost+"¥");
    }
}

输出结果:

开始调用喝茶...线程名:http-nio-80-exec-1
2023-02-24 15:12:38.072  INFO 24220 --- [p-nio-80-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
喝茶...线程名:SimpleAsyncTaskExecutor-1
it takes 100.0


springboot项目中

:启动类头上添加注解@EnableSync 要异步的方法上添加注解@Async

启动类

package com.async.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

controller

package com.async.demo.controller;

import com.async.demo.service.AsyncDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController("asyncDemo")
public class AsyncDemoController {

    @Autowired
    public AsyncDemoService asyncDemoService;

    @GetMapping("/takeTea")
    public String takeTea(double cost){
        System.out.println("开始调用喝茶...线程名:"+Thread.currentThread().getName());
        asyncDemoService.drinkTea(cost);
        asyncDemoService.drinkTea(cost);
        return "ok";
    }

}

service

package com.async.demo.service;

public interface AsyncDemoService {
    void drinkTea(double cost);
}

impl

package com.async.demo.service.impl;

import com.async.demo.service.AsyncDemoService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class AsynDemoServiceImpl implements AsyncDemoService {
    @Async
    @Override
    public void drinkTea(double cost) {
        System.out.println("喝茶...线程名:"+Thread.currentThread().getName());
        System.out.println("it takes "+cost+"¥");
    }
}

输出结果:

开始调用喝茶...线程名:http-nio-80-exec-1
2023-02-24 15:56:46.023  INFO 20336 --- [p-nio-80-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
喝茶...线程名:SimpleAsyncTaskExecutor-1
it takes 100.0¥
喝茶...线程名:SimpleAsyncTaskExecutor-2
it takes 100.0

以上是直接使用默认的线程池去启动一个线程执行异步方法。默认的线程池是SimpleAsyncTaskExecutor,这个不是真正的线程池,来一个任务就新建一个线程。不会自动回收,循环利用。


也可以自定义线程池


方式一:实现AsyncConfigurer接口

package com.async.demo.threadpool;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;


@Configuration
public class CustomThreadPool implements AsyncConfigurer {

    @Bean(name = "defaultExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(1);
        threadPoolTaskExecutor.setMaxPoolSize(5);
        threadPoolTaskExecutor.setQueueCapacity(3);
        threadPoolTaskExecutor.setThreadNamePrefix("task-executor-");
        threadPoolTaskExecutor.setKeepAliveSeconds(10);
        return threadPoolTaskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (Throwable e, Method method,Object... params)->{
            System.out.println("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
            System.out.println("type        : " + e.getClass().getName());
            System.out.println("exception   : " + e.getMessage());
        };
    }

    @Override
    public Executor getAsyncExecutor() {
        return threadPoolTaskExecutor();
    }
}

输出结果

开始调用喝茶...线程名:http-nio-80-exec-1
喝茶...线程名:task-executor-1
it takes 100.0¥
喝茶...线程名:task-executor-1
it takes 100.0

方式二:继承AsyncConfigurerSupport类

package com.async.demo.threadpool;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;

@Configuration
public class CustomThreadPool extends AsyncConfigurerSupport {

    @Bean(name = "defaultExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(1);
        threadPoolTaskExecutor.setMaxPoolSize(5);
        threadPoolTaskExecutor.setQueueCapacity(3);
        threadPoolTaskExecutor.setThreadNamePrefix("task-executor-");
        threadPoolTaskExecutor.setKeepAliveSeconds(10);
        return threadPoolTaskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (Throwable e, Method method,Object... params)->{
            System.out.println("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
            System.out.println("type        : " + e.getClass().getName());
            System.out.println("exception   : " + e.getMessage());
        };
    }

    @Override
    public Executor getAsyncExecutor() {
        return threadPoolTaskExecutor();
    }
}

输出结果

开始调用喝茶...线程名:http-nio-80-exec-1
喝茶...线程名:task-executor-1
it takes 100.0¥
喝茶...线程名:task-executor-1
it takes 100.0

可以在另外一个配置类中再配置一个线程池,取另外一个名字。写异步方法的时候,异步方法的注解@Async(name=“thread-pool-1”)中指明线程池的名字


异步方法返回值不为void为Future


如果异步方法需要返回值,返回值为Futrue,可通过isDone()查看按执行此异步方法的线程是否结束,通过get()获取执行结果。注意get方法会阻塞调用它的线程,知道获取到异步方法的返回值。

返回Futrue的方式

1、Futrue ExecutorService.submit(Callable callable);

2、Futrue ExecutorService.submit(Runable runable);

3、Futrue ExecutorService.submit(Runable runable,T result);result是调用时给出的默认值。

4、创建一个FutrueTask对象,将它传入Thread构造器中,从而创建一个线程。启动该线程,使用刚创建的FutrueTask对象获取异步方法的结果。

controller

package com.async.demo.controller;

import com.async.demo.service.AsyncDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;


@RestController("asyncDemo")
public class AsyncDemoController {

    @Autowired
    public AsyncDemoService asyncDemoService;

    @GetMapping("/takeTea")
    public String takeTea(double cost){
        System.out.println("开始调用喝茶...线程名:"+Thread.currentThread().getName());
        asyncDemoService.drinkTea(cost);
        asyncDemoService.drinkTea(cost);
        return "ok";
    }

    @GetMapping("/getAsync")
    public String getAsyncMethodResult(int type) throws ExecutionException, InterruptedException {
        Future<Boolean> f1 =  asyncDemoService.getAsyncMethodResult(type);
        return f1.get()?"success":"fail";
    }
    @GetMapping("/getAsync1")
    public String getAsyncMethodResult1(int type) throws ExecutionException, InterruptedException {
        Future<Boolean> f1 =  asyncDemoService.getAsyncMethodResult1(type);
        return f1.get()?"success":"fail";
    }
    @GetMapping("/getAsync2")
    public String getAsyncMethodResult2(int type) throws ExecutionException, InterruptedException {
        Future<Boolean> f1 =  asyncDemoService.getAsyncMethodResult2(type);
        return f1.get()?"success":"fail";
    }
    @GetMapping("/getAsync3")
    public String getAsyncMethodResul3(int type) throws ExecutionException, InterruptedException {
        Future<Boolean> f1 =  asyncDemoService.getAsyncMethodResult3(type);
        return f1.get()?"success":"fail";
    }
}

service

package com.async.demo.service.impl;

import com.async.demo.service.AsyncDemoService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.*;

@Service
public class AsynDemoServiceImpl implements AsyncDemoService {
    @Async("defaultExecutor")
    @Override
    public void drinkTea(double cost) {
        System.out.println("喝茶...线程名:"+Thread.currentThread().getName());
        System.out.println("it takes "+cost+"¥");
    }

    @Async("defaultExecutor")
    @Override
    public Future<Boolean> getAsyncMethodResult(int type) {
        System.out.println("线程名:"+Thread.currentThread().getName());
        ExecutorService executor =  Executors.newSingleThreadExecutor();
        Future<Boolean> future = executor.submit(()-> type==1 ?true : false);
        return future;
    }
    @Async("defaultExecutor")
    @Override
    public Future<Boolean> getAsyncMethodResult1(int type) {
        System.out.println("线程名:"+Thread.currentThread().getName());
        ExecutorService executor =  Executors.newSingleThreadExecutor();
        Future<Boolean> future = executor.submit(()->type==2?true:false);
        return future;
    }

    @Async("defaultExecutor")
    @Override
    public Future<Boolean> getAsyncMethodResult2(int type) {
        System.out.println("线程名:"+Thread.currentThread().getName());
        ExecutorService executor =  Executors.newSingleThreadExecutor();
        Future<Boolean> future = executor.submit(() -> System.out.println("type="+type),true);
        return future;
    }

    @Async("defaultExecutor")
    @Override
    public Future<Boolean> getAsyncMethodResult3(int type) {
        System.out.println("线程名:"+Thread.currentThread().getName());
        FutureTask ft = new FutureTask(()->type ==3 ? true : false);
        Thread a = new Thread(ft);
        a.start();
        return ft;
    }
}

AsyncResult是Futrue的实现类,在捕获异常的时候手动给异步方法返回一个值的时候可以使用这个类

/**
     * 异常调用返回Future
     *  对于返回值是Future,不会被AsyncUncaughtExceptionHandler处理,需要我们在方法中捕获异常并处理
     *  或者在调用方在调用Futrue.get时捕获异常进行处理
     *
     * @param i
     * @return
     */
    @Async
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture, parementer={}", i);
        Future<String> future;
        try {
            Thread.sleep(1000 * 1);
            future = new AsyncResult<String>("success:" + i);
        } catch (InterruptedException e) {
            future = new AsyncResult<String>("error");
        } catch(IllegalArgumentException e){
            future = new AsyncResult<String>("error-IllegalArgumentException");
        }
        return future;
    }



版权声明:本文为libing__123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。