我想使用多執行緒來加速 Spring 中 for 回圈代碼中的查詢。
有人說:執行緒池get方法是阻塞方法,所以和不寫執行緒沒什么區別。
那么這段代碼如何與 Java 回圈中的執行緒加速一起作業呢?
一些語言,比如C#,JS,使用await remoteCall(id),使用'await' 是否存在同樣的問題?
@Data
class ResultDto {
private BaseData baseData;
}
@Data
public class BaseData {
public String baseInfo;
public String remoteInfo;
}
ExecutorService exector = Executors.newCachedThreadPool();
public List<ResultDto> queryAll(List<String> ids) throws ExecutionException, InterruptedException {
List<ResultDto> res = new ArrayList<>();
for (String id : ids) {
ResultDto resultDto = new ResultDto();
BaseData baseData = new BaseData();
baseData.setBaseInfo("baseData" id);
//using thread blocking ?
String remoteResult = exector.submit(() -> remoteCall(id)).get();
baseData.setRemoteInfo(remoteResult);
resultDto.setBaseData(baseData);
res.add(resultDto);
}
return res;
}
String remoteCall(String id) {
return " httpUtils.get()" id;
}
由于我在多執行緒編程方面的經驗有限,我的代碼看起來很難看。如何改進它?請幫我重寫下面的代碼。
uj5u.com熱心網友回復:
做這樣的事情。
ExecutorService exector = Executors.newCachedThreadPool();
public List<ResultDto> queryAll(List<String> ids) throws ExecutionException, InterruptedException {
List<CompletableFuture> cfs = new ArrayList<>(ids.size());
for (String id : ids) {
CompletableFuture cf = Completableuture.supplyAsync(() -> getResult(id), exector);
cfs.add(cf);
}
CompletableFuture allOfThem = CompletableFuture.allOf(cfs.toArray(new CompletableFuture[0]);
CompletableFuture<List<ResultDto>> allCompletableFutures = allOfThem .thenApply(future -> {
return cfs.stream()
.map(completableFuture -> completableFuture.join())
.collect(Collectors.toList());
});
return allCompletableFutures.get();
}
ResultDto getResult(String id) {
String remoteResult = " httpUtils.get()" id;
BaseData baseData = new BaseData();
baseData.setBaseInfo("baseData" id);
baseData.setRemoteInfo(remoteResult);
ResultDto resultDto = new ResultDto();
resultDto.setBaseData(baseData);
return resultDto;
}
這將為您提供一個非阻塞解決方案(它最終只會阻塞)。
或者你可以讓它變得更簡單,只使用 aparallelStream并使用默認的 fork-join 池。
public List<ResultDto> queryAll(List<String> ids) throws ExecutionException, InterruptedException {
return ids.parallelStream().map(id -> getResult(id)).collect(Collectors.toList());
}
ResultDto getResult(String id) {
String remoteResult = " httpUtils.get()" id;
BaseData baseData = new BaseData();
baseData.setBaseInfo("baseData" id);
baseData.setRemoteInfo(remoteResult);
ResultDto resultDto = new ResultDto();
resultDto.setBaseData(baseData);
return resultDto;
}
您可能可以決定哪個更好讀...
uj5u.com熱心網友回復:
有人說:執行緒池get方法是阻塞方法,所以和不寫執行緒沒什么區別。
他們是正確的。如果您get()此時呼叫,它會立即阻塞,直到該特定任務完成。所以在第一個任務完成之前第二個任務不會提交......等等。
您需要做的是在呼叫之前提交所有任務get()。類似于以下偽代碼。
List<Future> futures
for each id in ids:
futures.add(executor.submit(...))
for each future in futures:
result = future.get()
results.add(process(result))
如果您可以安排每個任務處理其結果,您可能會獲得更多的并行性。
如前所述,您可以使用CompleteableFuture.allOf而不是第二個回圈。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/491170.html
