之前遇到一个需求,是需要请求区块链上面的block数据,进行数据解析然后入库存储,因为block产生一定时间后的数据都是固定的,链接不止一个,但返回的结果都是一样的,我只需要拿到首个返回的结果就好了,如果你也类似的场景,这篇文章或许能给你到参考
工具类
package com.yianjia.common.utils;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
/**
* @author z
*/
@Component
public class FastFirstRequestUtils {
private static final Logger logger = LoggerFactory.getLogger(FastFirstRequestUtils.class);
private List<String> urlList = Arrays.asList(
"https://www.baidu.com",
"https://www.baidu.com",
"https://www.baidu.com",
"https://www.baidu.com",
"https://www.baidu.com"
);
private static ExecutorService executorService = new ThreadPoolExecutor(0, 128, 0L, TimeUnit.SECONDS, new SynchronousQueue<>(), (new ThreadFactoryBuilder()).setNameFormat("get_url-1-%d").build());
@Autowired
private RestTemplateUtils restTemplateUtils;
@PostConstruct
public void run() {
CompletableFuture[] futures = this.urlList.stream().map((url) -> CompletableFuture.supplyAsync(() -> {
// 替换成你自己的请求
String getBlockResult = this.restTemplateUtils.exchange(url, HttpMethod.POST, null, null, null, String.class);
return getBlockResult;
}, executorService).exceptionally((e) -> null)).toArray((size) -> new CompletableFuture[size]);
// n 为完成数,只要完成数达到,就会返回结果集,不会阻塞
CompletableFuture completableFuture = firstSuccessful(Arrays.asList(futures), 1);
List<String> resultList = null;
try {
resultList = (List) completableFuture.get(5L, TimeUnit.SECONDS);
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
} catch (ExecutionException executionException) {
executionException.printStackTrace();
} catch (TimeoutException timeoutException) {
timeoutException.printStackTrace();
}
if (null != resultList && 0 != resultList.size()) {
System.out.println("-------------------结果出来啦-------------------");
System.out.println(resultList.get(0));
System.out.println("-------------------结果出来啦-------------------");
}
}
/**
* @param list 任务集
* @param n 需要完成的任务数
* @param <T>
* @return
*/
private static <T> CompletableFuture<List<T>> firstSuccessful(List<CompletableFuture<T>> list, int n) {
int maxFail = list.size() - n;
if (maxFail < 0 || n <= 0) {
throw new IllegalArgumentException();
}
AtomicInteger counter = new AtomicInteger(1);
AtomicInteger fails = new AtomicInteger(0);
List<T> rList = new ArrayList(n);
CompletableFuture<List<T>> result = new CompletableFuture();
BiConsumer<T, Throwable> c = (value, failure) -> {
if (n != rList.size()) {
if (failure != null) {
if (fails.incrementAndGet() > maxFail) {
result.completeExceptionally(failure);
}
} else if (!result.isDone()) {
boolean commit = false;
synchronized (rList) {
if (null != value) {
commit = rList.size() < n && rList.add(value) && rList.size() == n;
}
}
if (commit) {
result.complete(Collections.unmodifiableList(rList));
return;
}
}
if (counter.get() == list.size()) {
result.complete(Collections.unmodifiableList(rList));
} else {
counter.incrementAndGet();
}
}
};
for (CompletableFuture<T> tCompletableFuture : list) {
CompletableFuture f = tCompletableFuture;
f.whenComplete(c);
}
return result;
}
}