Spring @Async

在Spring中可以使用@Async注解标记类或方法,有@Async注解的类会生成代理对象,代理对象会将有@Async注解的方法(异步方法)放在线程池里面异步执行;

@Async注解的方法返回值类型可以是void,也可以是Future类型,如果是普通类型则获取不到异步执行结果;

Spring默认使用的SimpleAsyncTaskExecutor线程池不会重用线程,并且没有最大线程数的限制,在大并发量的时候存在性能问题,所以Spring使用自定义线程池配合@Async注解一起使用;

一 简单使用

在配置类中添加@EnableAsync注解;

在业务类中需要异步执行的方法上添加@Async注解;

1.1 方法返回值类型是void

java 复制代码
@Configuration
@EnableAsync
public class CommonConfig {

}

@Service
public class OrderService {
    public void printOrderMsgOne() {
        try {
            // 模拟线程任务执行
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message one...");
    }

    @Async
    public void printOrderMsgTwo() {
        try {
            // 模拟线程任务执行
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message two...");
    }
}

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/one")
    public String orderOne() {
        System.out.println(Thread.currentThread().getName()
                + " 线程开始执行任务...");
        System.out.println("输出printOrderMsgOne方法信息: ");
        orderService.printOrderMsgOne();
        System.out.println("输出printOrderMsgTwo方法信息: ");
        orderService.printOrderMsgTwo();
        // 模拟线程任务执行
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()
                + " 线程结束执行任务...");
        return "success";
    }

}

方法执行结果:

http-nio-8081-exec-2 线程开始执行任务...
输出printOrderMsgOne方法信息:
http-nio-8081-exec-2 输出message one...
输出printOrderMsgTwo方法信息:
http-nio-8081-exec-2 线程结束执行任务...
task-1 输出message two...

orderOne方法在http-nio-8081-exec-2线程中执行,printOrderMsgTwo方法在task-1个线程异步执行;

1.2 方法返回值类型是普通类型

java 复制代码
@Configuration
@EnableAsync
public class CommonConfig {

}

@Service
public class OrderService {
    public void printOrderMsgOne() {
        try {
            // 模拟线程任务执行
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message one...");
    }

    @Async
    public String printOrderMsgTwo() {
        try {
            // 模拟线程任务执行
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message two...");
        return "printOrderMsgTwo successfully";
    }
}

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/one")
    public String orderOne() {
        System.out.println(Thread.currentThread().getName()
                + " 线程开始执行任务...");
        System.out.println("输出printOrderMsgOne方法信息: ");
        orderService.printOrderMsgOne();
        System.out.println("输出printOrderMsgTwo方法信息: ");
        String str = orderService.printOrderMsgTwo();
        // 模拟线程任务执行
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("异步执行结果: " + str);
        System.out.println(Thread.currentThread().getName()
                + " 线程结束执行任务...");
        return "success";
    }

}

方法执行结果:

http-nio-8081-exec-1 线程开始执行任务...

输出printOrderMsgOne方法信息:

http-nio-8081-exec-1 输出message one...

输出printOrderMsgTwo方法信息:

异步执行结果: null

http-nio-8081-exec-1 线程结束执行任务...

task-1 输出message two...

在orderOne方法中获取不到printOrderMsgTwo方法异步执行的结果,无论printOrderMsgTwo方法在orderOne方法响应之前完成还是之后完成,都获取不到printOrderMsgTwo方法的异步执行结果;

1.3 方法返回值类型是Future

java 复制代码
@Configuration
@EnableAsync
public class CommonConfig {

}

@Service
public class OrderService {
    public void printOrderMsgOne() {
        try {
            // 模拟线程任务执行
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message one...");
    }

    @Async
    public Future<String> printOrderMsgTwo() {
        try {
            // 模拟线程任务执行
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message two...");
        return new AsyncResult<>("printOrderMsgTwo successfully");
    }
}

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/one")
    public String orderOne() {
        System.out.println(Thread.currentThread().getName()
                + " 线程开始执行任务...");
        System.out.println("输出printOrderMsgOne方法信息: ");
        orderService.printOrderMsgOne();
        System.out.println("输出printOrderMsgTwo方法信息: ");
        Future<String> future = orderService.printOrderMsgTwo();
        // 模拟线程任务执行
        try {
            Thread.sleep(3000);
            String str = future.get();
            System.out.println("异步执行结果: " + str);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()
                + " 线程结束执行任务...");
        return "success";
    }

}

方法执行结果:

http-nio-8081-exec-2 线程开始执行任务...

输出printOrderMsgOne方法信息:

http-nio-8081-exec-2 输出message one...

输出printOrderMsgTwo方法信息:

task-2 输出message two...

异步执行结果: printOrderMsgTwo successfully

http-nio-8081-exec-2 线程结束执行任务...

orderOne方法在http-nio-8081-exec-2线程中执行,printOrderMsgTwo在task-2线程中执行;

printOrderMsgTwo的方法返回值类型是Future,Future中的get方法是阻塞方法,所以orderOne方法会一直阻塞直到获得异步执行结果才会响应;

二 自定义线程池

@Async注解的value属性用来指定使用具体的线程池

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
    String value() default "";
}
java 复制代码
@Configuration
@EnableAsync
public class CommonConfig {

    @Bean("threadPoolOne")
    public ThreadPoolTaskExecutor threadPool() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(10);
        threadPool.setMaxPoolSize(15);
        threadPool.setQueueCapacity(15);
        threadPool.setKeepAliveSeconds(60);
        return threadPool;
    }

    @Bean("threadPoolTwo")
    public ThreadPoolTaskExecutor threadPoolTwo() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(10);
        threadPool.setMaxPoolSize(15);
        threadPool.setQueueCapacity(15);
        threadPool.setKeepAliveSeconds(60);
        return threadPool;
    }

}

@Service
public class OrderService {
    public void printOrderMsgOne() {
        try {
            // 模拟线程任务执行
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message one...");
    }

    @Async("threadPoolTwo")
    public CompletableFuture<String> printOrderMsgTwo() {
        try {
            // 模拟线程任务执行
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("\t" + Thread.currentThread().getName()
                + " 输出message two...");
        return CompletableFuture.completedFuture("printOrderMsgTwo successfully");
    }
}


@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/one")
    public String orderOne() {
        System.out.println(Thread.currentThread().getName()
                + " 线程开始执行任务...");
        System.out.println("输出printOrderMsgOne方法信息: ");
        orderService.printOrderMsgOne();
        System.out.println("输出printOrderMsgTwo方法信息: ");
        CompletableFuture<String> future = orderService.printOrderMsgTwo();
        // 模拟线程任务执行
        try {
            Thread.sleep(3000);
            String str = future.get();
            System.out.println("异步执行结果: " + str);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()
                + " 线程结束执行任务...");
        return "success";
    }

}

方法执行结果:

http-nio-8081-exec-1 线程开始执行任务...

输出printOrderMsgOne方法信息:

http-nio-8081-exec-1 输出message one...

输出printOrderMsgTwo方法信息:

threadPoolTwo-1 输出message two...

异步执行结果: printOrderMsgTwo successfully

http-nio-8081-exec-1 线程结束执行任务...

orderOne方法用的是http-nio-8081-exec-1线程,printOrderMsgTwo方法用的threadPoolTwo线程池里面的线程;

相关推荐
AiFlutter15 分钟前
Java实现简单的搜索引擎
java·搜索引擎·mybatis
飞升不如收破烂~36 分钟前
Spring boot常用注解和作用
java·spring boot·后端
秦老师Q36 分钟前
Java基础第九章-Java集合框架(超详细)!!!
java·开发语言
计算机毕设源码qq-383653104138 分钟前
(附项目源码)Java开发语言,215 springboot 大学生爱心互助代购网站,计算机毕设程序开发+文案(LW+PPT)
java·开发语言·spring boot·mysql·课程设计
ashane131441 分钟前
Java list
java·windows·list
袁庭新1 小时前
Cannal实现MySQL主从同步环境搭建
java·数据库·mysql·计算机·java程序员·袁庭新
无尽的大道1 小时前
深入理解 Java 阻塞队列:使用场景、原理与性能优化
java·开发语言·性能优化
何遇mirror1 小时前
云原生基础-云计算概览
后端·云原生·云计算
岁岁岁平安1 小时前
springboot实战(15)(注解@JsonFormat(pattern=“?“)、@JsonIgnore)
java·spring boot·后端·idea
Oak Zhang1 小时前
TheadLocal出现的内存泄漏具体泄漏的是什么?弱引用在里面有什么作用?什么情景什么问题?
java·系统安全