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

相关推荐
向前看-1 小时前
验证码机制
前端·后端
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石3 小时前
12/21java基础
java
李小白663 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp3 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea