Springboot2整合线程池@Async异步应用场景

一.为何要使用异步?

1.在许多业务场景中,比如你的代码中有3个查询不同数据的方法或者去其他接口需要时间去调用,那么ABC3个接口,不是异步的情况,肯定是需要你执行A完成之后,再执行B,然后再执行C方法。那么用的时长就会很久了。所以使用异步+多线程来实现请求的时候会有3个线程去执行ABC3个方法。那么实际的时间将会缩短。

2.@Async有2种返回机制。

无返回值类型(调用直接返回,不会在意此方法执行用时,直接返回结果给客户端)

有返回值类型(返回类型为Future<T>类型或者他的子类,因为需要他来里面的方法来判断方法是否执行完成了。)

异步的话,比如发送短信,我们平时发短信都是,点击发送立马就有发送成功的提升了,但是在代码中肯定处理没有这么快,所以在方法中使用了@Async直接返回结果了,如果短信业务出现问题,可以根据业务来给你提示未送达等信息。

3.需要返回值的就需要调用Future<T>中的方法去判断是否执行完成和获取返回值等一系列操作。

二.添加pom文件

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

三.创建自定义线程池的配置类

@Configuration
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
    // 声明一个线程池(并指定线程池的名字,默认是方法名称)
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数5:线程池创建时候初始化的线程数
        executor.setCorePoolSize(5);
        //最大线程数5:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(5);
        //缓冲队列大小:用来缓冲执行任务的队列
        executor.setQueueCapacity(500);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("线程名-");

          //不在新线程中执行任务,而是用调用者所在的线程来执行
        // executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();

        return executor;

    }
    //异常处理
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new MyAsyncUncaughtExceptionHandler();
    }
}
    class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable ex, Method method, Object... params) {

            System.out.println("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
            System.out.println("type        : " + ex.getClass().getName());
            System.out.println("exception   : " + ex.getMessage());

        }
    }

四.编写service

@Service
public class BmtOrderThread { 
       
    @Async("taskExecutor")
    public Future<Map<String,Object>> test1() {
        Map<String,Object> result=new HashMap<String,Object>();
        AsyncResult<Map<String, Object>> asyncResult = new AsyncResult<>(result);

        // get方法:获取计算结果(如果还没计算完,也是必须等待的)

        //cancel方法:还没计算完,可以取消计算过程

        //isDone方法:判断是否执行完成

       // isCancelled方法:判断计算是否被取消
        return new AsyncResult<>(result);
    } 
       
    @Async("taskExecutor")
    public Future<Boolean> test2()throws Exception {
        System.out.println("开始..........test2"+Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println("结束..........test2");
        return new AsyncResult<>(true);
    }

    @Async("taskExecutor")
    public Future<Boolean> test3()throws Exception {
        System.out.println("开始..........test3"+Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println("结束..........test3");
        return new AsyncResult<>(true);
    }

    //异步调用,有返回值,必须是Future类型,不然报错
    @Async("taskExecutor")
    public Future<String> getTotalHitsFuture()  {
        System.out.println("开始执行");
        Future<String> future;
        try {

            System.out.println("正在请求短信接口 . ");
            Thread.sleep(1000);
            System.out.println("正在发送!");
            int a=12/0;
            System.out.println("发送完成!");
            future=new AsyncResult<>("success");
        } catch (Exception e) {
            System.out.println("发送失败出现异常:"+e);
            future=new AsyncResult<>("error");
        }

        return  future;
    }

五.测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMultithreadingApplicationTests {

    @Autowired
    BmtOrderThread bmtOrderThread;

    @Test
    public void test() {
            Future<String> future = bmtOrderThread.getTotalHitsFuture();
            try {
                Thread.sleep(1000);
                String s = future.get();
                if ("success".equals(s)){
                    System.out.println("短信发送成功之后的业务");
                }else{
                    System.out.println("发送失败之后的业务");
                }
            } catch (Exception e) {
                System.out.println(e);
            }
    }
    @Test
    public  void test2(){
        try {
            long start = System.currentTimeMillis();
            Future<Boolean> a = bmtOrderThread.test2();
            Future<Boolean> b = bmtOrderThread.test3();
            while (!a.isDone() || !b.isDone()) {
                if (a.isDone() && b.isDone()) {
                    break;
                }
            }
            long end = System.currentTimeMillis();
            String times = "任务全部完成,总耗时:" + (end - start) + "毫秒";
            System.out.println(times);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6.测试test

开始执行
正在请求短信接口 . 
正在发送!
发送失败出现异常:java.lang.ArithmeticException: / by zero
发送失败之后的业务

测试test2

开始..........test2线程名-1
开始..........test3线程名-2
结束..........test3
结束..........test2
任务全部完成,总耗时:5007毫秒

猜你喜欢

转载自blog.csdn.net/qq_41085151/article/details/107632427