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

相关推荐
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
码农小旋风3 小时前
详解K8S--声明式API
后端
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616884 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7894 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java5 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet