async异步返回结果、实现多线程查询数据

最近做大屏,需要调用很多接口,发现调用接口很慢,所以考虑到一个比较简单的方法,使用springboot自带异步返回值,减少接口调用时间。

Async的异步方法和调用异步的方法不能在同一个类里面,否则异步失效,所以创建一个异步的类,用来放异步和方法。

1、设置多线程的配置

package com.ruoyi.modelfile.ruoyimodelfile.config;

import lombok.NoArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;

/**
 * @className ExecutorConfig
 * @Description: 设置多线程的配置   学习链接:https://blog.csdn.net/weixin_41155095/article/details/123790202
 * @Author ljquan
 * @Date 2022/05/19 11:22:14
 * @Version 1.0.0
 */
@Configuration
@EnableAsync
@NoArgsConstructor
public class ExecutorConfig {
    /**
     * 设置 ThreadPoolExecutor 的核心池大小.
     */
    private static final int corePoolSize = 10;
    /**
     * 设置 ThreadPoolExecutor 的最大池大小.
     */
    private static final int maxPoolSize = 200;
    /**
     * 设置 ThreadPoolExecutor 的 BlockingQueue 的容量.
     */
    private static final int queueCapacity = 10;

    /**
     * 异步一  【自定义线程池执行器】
     *
     * @return {@code Executor}
     */
    @Bean(name = "Async1")
    public Executor Async1() {
        //线程池任务执行器  创建一个线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心池大小
        executor.setCorePoolSize(corePoolSize);
        //设置最大池大小
        executor.setMaxPoolSize(maxPoolSize);
        //设置队列容量
        executor.setQueueCapacity(queueCapacity);
        //设置线程前缀
        executor.setThreadNamePrefix("测试线程demo1-");
        executor.initialize();
        return executor;
    }

    /**
     * async2
     *
     * @return {@code Executor}
     */
    @Bean(name = "Async2")
    public Executor Async2() {
        //线程池任务执行器  创建一个线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心池大小
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        //设置队列容量
        executor.setQueueCapacity(queueCapacity);
        //设置线程前缀
        executor.setThreadNamePrefix("测试线程demo2-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

        //设置拒绝执行处理程序
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化
        executor.initialize();
        return executor;
    }

    //    类似的如果还有其他线程,也可以继续给其他线程配置对应的线程池

    //
    // /**
    //  * 执行周期性或定时任务
    //  *
    //  * @return {@code ScheduledExecutorService}
    //  */
    // @Bean(name = "scheduledExecutorService2")
    // protected ScheduledExecutorService scheduledExecutorService() {
    //     return new ScheduledThreadPoolExecutor(corePoolSize,
    //             new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
    //             new ThreadPoolExecutor.CallerRunsPolicy()) {
    //         @Override
    //         protected void afterExecute(Runnable r, Throwable t) {
    //             super.afterExecute(r, t);
    //             Threads.printException(r, t);
    //         }
    //     };
    // }




    // 线程池构建
    private volatile static ExecutorService executorService;

    /**
     * 获取共享的线程池实例。如果不存在,则创建一个新实例。
     *
     * @return 表示线程池的 ExecutorService 实例。
     */
    public static ExecutorService getThreadPool() {
        if (executorService == null) {
            synchronized (ExecutorConfig.class) {
                if (executorService == null) {
                    executorService = newThreadPool();
                }
            }
        }
        return executorService;
    }

    /**
     * 使用指定参数创建新的线程池。
     *
     * @return 表示线程池的新 ExecutorService 实例。
     */
    private static ExecutorService newThreadPool() {
        int queueSize = 500;
        int corePool = Math.min(5, maxPoolSize); // 根据需求调整核心池大小
        // 根据需求定义最大池大小
        return new ThreadPoolExecutor(corePool, maxPoolSize, 10000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(queueSize), new ThreadPoolExecutor.AbortPolicy());
    }




//

    private volatile static Executor executor;
    public static Executor getExecutor() {
        if (executor == null) {
            synchronized (ExecutorConfig.class) {
                if (executor == null) {
                    executor = newExecutor();
                }
            }
        }
        return executor;
    }

    private static Executor newExecutor() {
        //线程池任务执行器  创建一个线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心池大小
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        //设置队列容量
        executor.setQueueCapacity(queueCapacity);
        //设置线程前缀
        executor.setThreadNamePrefix("新建测试Executor-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

        //设置拒绝执行处理程序
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化
        executor.initialize();
        return executor;
    }


    @Bean("threadPoolTaskExecutor")//自定义线程池名称
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //线程池创建的核心线程数,线程池维护线程的最少数量,即使没有任务需要执行,也会一直存活
        executor.setCorePoolSize(16);

        //如果设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
        //executor.setAllowCoreThreadTimeOut(true);

        //阻塞队列 当核心线程数达到最大时,新任务会放在队列中排队等待执行
        executor.setQueueCapacity(124);
        //最大线程池数量,当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
        //任务队列已满时, 且当线程数=maxPoolSize,,线程池会拒绝处理任务而抛出异常
        executor.setMaxPoolSize(64);
        executor.setKeepAliveSeconds(30);
        executor.setThreadNamePrefix("自定义线程池-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }
}

2、创建异步类

package com.ruoyi.modelfile.ruoyimodelfile.mybatisPlus.asyncServiceIpmpl;


import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;

/**
 * @className AsyncTest
 * @描述 RuoYi-Vue-Test
 * @Author ljquan
 * @Date 2023/8/26 15:55 星期六
 */
@Slf4j
@Component
public class AsyncTest {

    public static void main(String[] args) {
        // 在 main 方法中编写您的代码逻辑
    }


    @Async("Async2")
    public CompletableFuture<String> test() throws InterruptedException {
        //开始写代码吧
        Thread.sleep(6000);
        System.out.println(Thread.currentThread().getId());
        return CompletableFuture.completedFuture("333");
    }

    @Async("Async2")
    public CompletableFuture<String> test2() throws InterruptedException {
        //开始写代码吧
        Thread.sleep(300);
        System.out.println(Thread.currentThread().getId());
        return CompletableFuture.completedFuture("3444");
    }

    @Async("Async2")
    public CompletableFuture<String> test4() throws InterruptedException {
        //开始写代码吧
        Thread.sleep(300);
        System.out.println(Thread.currentThread().getId());
        return CompletableFuture.completedFuture("4444");
    }

    @Async("Async2")
    public CompletableFuture<String> test5() throws InterruptedException {
        //开始写代码吧
        Thread.sleep(300);
        System.out.println(Thread.currentThread().getId());
        return CompletableFuture.completedFuture("5555");
    }


    @Async("Async2")
    public CompletableFuture<String> test3() throws InterruptedException {
        //开始写代码吧
        Thread.sleep(12000);
        System.out.println("5"+Thread.currentThread().getId());
        return CompletableFuture.completedFuture("2222");
    }


}

3、使用异步方法,实现调用



@Resource
AsyncTest asyncTest;

@Test
public void test() {
    System.out.println("test");
    //开始写代码吧
    long l = System.currentTimeMillis();
    ArrayList<String> strings = new ArrayList<>();
    try {
        List<CompletableFuture<String>> completableFutures = new ArrayList<>();
        CompletableFuture<String> task1 = asyncTest.test();
        CompletableFuture<String> task2 = asyncTest.test2();
        CompletableFuture<String> task3 = asyncTest.test3();
        CompletableFuture<String> task4 = asyncTest.test4();
        CompletableFuture<String> task5 = asyncTest.test5();
        completableFutures.add(task1);
        completableFutures.add(task2);
        completableFutures.add(task3);
        completableFutures.add(task4);
        completableFutures.add(task5);

        // 让所有的task执行完成才可以调用
        CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
        strings.add(task1.get());
        strings.add(task2.get());
        strings.add(task3.get());
        strings.add(task4.get());
        strings.add(task5.get());


    } catch (InterruptedException | ExecutionException e) {
        throw new RuntimeException(e);
    }
    long l1 = System.currentTimeMillis() - l;
    System.out.println("完成花费的时间:"+l1 + "mm");
    System.out.println(strings.toString());
}


CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
这一行很重要,等待所有的task都执行完成再进行下一步。

4、结果

可以得到结果,有返回值,打印时间,是异步方法里面的最大的时间,说明是异步,时间不叠加。Async实现异步返回值。

test
29
27
30
26
528
完成花费的时间:12012mm
[333, 3444, 2222, 4444, 5555]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
引用\[1\]:在Spring Boot中实现多线程异步可以通过使用注解来实现。首先,在启动类上加上注解@EnableAsync,这样就开启了异步功能。然后,在想要异步执行的方法上加上注解@Async,表示该方法是异步的。最后,在主函数中调用该方法即可实现异步执行。Spring Boot真的很方便,只需要这两个注解就可以完成异步操作。\[1\] 引用\[2\]:另外,可以通过设置corePoolSize来控制线程池的大小,从而实现更好的线程管理。例如,将corePoolSize设置为10,重启Spring Boot后,可以使用Jmeter同时调用接口多次,观察控制台日志可以看到多个线程同时执行,这样可以提高程序的运行效率。\[2\] 总结起来,Spring Boot实现多线程异步的步骤如下: 1. 在启动类上加上注解@EnableAsync,开启异步功能。 2. 在想要异步执行的方法上加上注解@Async,表示该方法是异步的。 3. 在主函数中调用该方法即可实现异步执行。 4. 可以通过设置corePoolSize来控制线程池的大小,以优化线程管理。\[1\]\[2\] #### 引用[.reference_title] - *1* [springboot实现线程异步](https://blog.csdn.net/qq_38403590/article/details/119729294)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Springboot异步多线程编程](https://blog.csdn.net/baidu_28340727/article/details/122310314)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值