项目场景:
通过注册好的设备序列 请求第三方接口(每台设备每秒最多请求1~2次)获取数据,并且需要合理调度尽可能不浪费空余间隔时间;
废话不多说直接上代码
maven依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
测试类
@Slf4j
public class Test {
/**
* 创建一个自适应服务器配置的线程池
*/
private static ThreadPoolExecutor eventQueueService = new ThreadPoolExecutor(
20,
20 * Runtime.getRuntime().availableProcessors(),
60L,
TimeUnit.SECONDS,
// 这里可以根据实际业务设定队列数量,默认大小是Integer.MAX_VALUE
new LinkedBlockingDeque<>(),
new ThreadFactoryBuilder().setNameFormat("zgt-pool-%d").setDaemon(true).build(),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
/**
* 注册设备序列
*/
public static List<Integer> registerDevSerial = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
/**
* guava rateLimiter限流算法
*/
public static LoadingCache<String, RateLimiter> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(1, TimeUnit.DAYS)
.build(new CacheLoader<String, RateLimiter>() {
@Override
public RateLimiter load(String key) {
// 同一key每秒限制1个令牌
return RateLimiter.create(2);
}
});
/**
* 轮询随机设备序列
*
*/
public synchronized static int randomDevSerial() {
// 随机数
Random random = new Random();
int index = random.nextInt(registerDevSerial.size());
int num = registerDevSerial.get(index);
AtomicReference<String> key = new AtomicReference<>("");
try {
RateLimiter rateLimiter = cache.get(key.get());
if (!rateLimiter.tryAcquire()) {
TimeUnit.MILLISECONDS.sleep(10);
return randomDevSerial();
}
} catch (ExecutionException | InterruptedException e) {
log.error(e.getMessage(), e);
}
return num;
}
@SneakyThrows
private static String service() {
log.info("进入服务{}", randomDevSerial());
TimeUnit.MILLISECONDS.sleep(100);
return "success";
}
public static void main(String[] args) {
List<CompletableFuture<String>> futureLs = new ArrayList<>();
// 模拟需要查询的1w条数据
for (int i = 0; i < 10000; i++) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(Test::service, eventQueueService);
futureLs.add(future);
}
List<String> collect = futureLs.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
System.out.println(collect.size());
}
}