最近做大屏,需要调用很多接口,发现调用接口很慢,所以考虑到一个比较简单的方法,使用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]