接口优化方案
一、并发编程
场景:性能不达标接口内部串行调用,优化方案:调整为并发调用
案例如下:
pom文件配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.demo</groupId>
<artifactId>java_base</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java_base</name>
<description>java_base</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.36</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>cn.demo.java_base.JavaBaseApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
两种方式完成接口的并发调用,参看方法:
方法一:通过Callable创建任务,结合线程池实现并发调用,参看方法:testCallable
方法二:通过Completable的任务编排作用,结合线程池实现并发调用,参看方法:testCompletableFutures
两者获取结果时会产生阻塞,所以建议异步调用完全部接口后统一获取结果。
该方案优化场景适用于有性能瓶颈的接口,通过方法调用链路排查出内部服务调用耗时较长,可以调整为并行调用。
/**
* @Auther: gina
* @Date: 2025-03-06
* @Description:并发处理测试
*/
@SpringBootTest
public class CallableTest {
private static final Logger log = LoggerFactory.getLogger(CallableTest.class);
//线程池+多个Callable创建的任务,并发调用
@Test
void testCallable() throws InterruptedException, ExecutionException {
//创建线程池
ExecutorService es = Executors.newFixedThreadPool(3);
Date start = new Date();
//使用Callable创建多任务
List<Callable<String>> tasks = new ArrayList<>();
tasks.add(() -> {
return a100();
});
tasks.add(() -> {
return b200();
});
tasks.add(() -> {
return c230();
});
List<Future<String>> futures = es.invokeAll(tasks);
String a100 = futures.get(0).get();
String b200 = futures.get(1).get();
String c230 = futures.get(2).get();
Date endTime = new Date();
Long consTime = endTime.getTime() - start.getTime();
es.shutdown();
log.info("testCallable:: a100={},b200={},c230={},累计消耗时间{}", a100, b200, c230, consTime);
}
@Test
void testCompletableFutures() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService es = Executors.newFixedThreadPool(3);
Date start = new Date();
//使用Callable创建多任务
CompletableFuture<String> aFuture = CompletableFuture.supplyAsync(() -> {
try {
return a100();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, es);
CompletableFuture<String> bFuture = CompletableFuture.supplyAsync(() -> {
try {
return b200();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, es);
CompletableFuture<String> cFuture = CompletableFuture.supplyAsync(() -> {
try {
return c230();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, es);
String a100 = aFuture.get();
String b200 = bFuture.get();
String c230 = cFuture.get();
Date endTime = new Date();
Long consTime = endTime.getTime() - start.getTime();
es.shutdown();
log.info("CompletableFuture:: a100={},b200={},c230={},累计消耗时间{}", a100, b200, c230, consTime);
}
private String c230() throws InterruptedException {
Thread.sleep(230);
return "ok";
}
private String b200() throws InterruptedException {
Thread.sleep(200);
return "ok";
}
private String a100() throws InterruptedException {
Thread.sleep(100);
return "ok";
}
}
执行结果分别为:
testCallable:: a100=ok,b200=ok,c230=ok,累计消耗时间236
CompletableFuture:: a100=ok,b200=ok,c230=ok,累计消耗时间237
由此,接口的响应时间只取决于调用服务里,最长的那个。若还是不满足,可以从sql优化,或者缓存等方面,具体看瓶颈进行分析。
持续更新中…