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线程池里面的线程;

相关推荐
2601_962071573 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
zww89491114 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·eclipse
东风破_5 小时前
从跨域到 WebSocket:前端跨域方案、SSE 与双向实时通信详解
前端·后端
zww89491116 小时前
匿名树洞系统开发实战:从需求分析到部署指南
java·eclipse
行百里er6 小时前
Gateway 上别硬塞 MVC:DeferredImportSelector 看菜下锅
spring boot·后端·开源
名字还没想好☜7 小时前
Java 遍历时删元素抛 ConcurrentModificationException:fail-fast 原理与三种正确删法
后端
IT_陈寒7 小时前
React Hooks闭包陷阱差点让我加班到凌晨
前端·人工智能·后端
黑马程序员毕设7 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
木井巳8 小时前
【BFS/DFS 解决 FloodFill 算法】太平洋大西洋水流问题
java·算法·leetcode·深度优先·广度优先·宽度优先·推荐算法
码事漫谈8 小时前
本体论,彻底懂
后端