我有一个 REST API,我应该从外部 API 获取大量数据。我决定尝试多线程来优化整个获取-解析-持久周期。但我在 ExecutorService 方面遇到了麻烦(在这项工作之前我没有使用过它)。我正在分享整个过程的类(class)和相关部分
public class LogRetrievingService implements Runnable {
CustomHttpClient client;
public LogRetrievingService(CustomHttpClient client) {
this.client = client;
}
@Override
public void run() {
Response response = client.invokeExternalApi();
parse(response.readEntity(bytes[].class);
}
//skipping parse() for brevity, it basically selects some columns and sends them to DBwriter
我的REST API资源是这样的
public class LogRetrieverResource {
private CustomHttpClient client;
public LogRetrieverResource(CustomHttpClient client) {
this.client = client;
}
//this does not work
public void initLogRetrieval() {
ExecutorService service = Executors.newFixedThreadPool(4); //max_thread
for(int i = 0; i < 4; i++) {
service.submit(new LogRetrievingService (client));
}
}
//THIS WORKS
public void initLogRetrieval() {
for(int i = 0; i < 4; i++) {
Thread thread = new Thread(new LogRetrievingService(client));
thread.start();
}
}
}
现在,当我访问资源时,没有任何反应,我可以看到客户端的日志已被访问,但它不会去获取数据。
但是,如果在我的 LogRetrieverResource 类的循环中,我使用相同的运行方法创建一个新的 Thread 实例,则多线程数据提取将按预期工作。有人可以指出我做错了什么吗?除了实现 Runnable
接口(interface)方法之外,我之前没有在 java 中使用多线程的经验。
编辑:添加客户端类详细信息
import javax.ws.rs.client.Client;
public class CustomHttpClient {
public Response invokeExternalAPI() {
return client
.target("url") //removing url for confidentiality
.request()
.accept(MediaType.APPLICATION_JSON)
.cookie("SSO",<token>)
.get();
}
}
最佳答案
只是想注意差异,应该不会有太大差异。首先在执行程序提交循环的末尾添加 service.shutdown()
。那么你几乎会做同样的事情。
下一期,异常的处理方式略有不同。执行器服务将捕获所有异常。出于调试目的,您可以尝试。
service.submit(
() -> {
try{
new LogRetrievingService (client).run();
} catch(Exception e){
//log the exception so you can see if anything went wrong.
}
});
但这不是使用 ExecutorService 处理异常的方法,您应该获取提交的 future 并使用它来处理任何错误。另外,我怀疑 spring 有一些工具可以完成此类工作。
关于java - ExecutorService 不起作用,但单独创建线程可以,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60599874/