You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Awaitility异步测试高内存问题,寻求低内存替代方案

寻找Awaitility的低内存替代方案

可行的低内存替代方案

1. 优化Awaitility的线程复用(最小改动方案)

Awaitility默认会为每个等待逻辑创建新线程,导致大规模测试时内存飙升。但可以通过配置全局复用的自定义线程池,避免线程频繁创建销毁的内存开销:

// 全局初始化可复用的线程池,根据测试并发量调整核心线程数
private static final ScheduledExecutorService CUSTOM_SCHEDULER = Executors.newScheduledThreadPool(4);

static void optimizedWaitWithAwaitility() {
    AtomicInteger primeCount = new AtomicInteger(0);
    await()
        .with().scheduler(CUSTOM_SCHEDULER) // 指定自定义线程池
        .atMost(1, TimeUnit.HOURS)
        .pollInterval(3, TimeUnit.SECONDS)
        .until(() -> {
            int number = supplierMethod().get();
            if (isPrime(number)) {
                System.out.println("Found prime: " + number);
                primeCount.incrementAndGet();
            }
            return primeCount.get() >= 500;
        });
}

// 测试套件结束后关闭线程池,避免资源泄漏
@AfterClass
public static void cleanupScheduler() {
    CUSTOM_SCHEDULER.shutdown();
}

该方案完全保留Awaitility的API使用习惯,仅需添加线程池配置,即可大幅降低内存占用。

2. 基于Java原生API实现轻量轮询(无第三方依赖)

如果想彻底摆脱第三方库的内存开销,可以用Java原生的ScheduledExecutorService+CountDownLatch实现自定义等待逻辑,完全控制线程数量:

static void customWaitWithNativeJava() throws InterruptedException {
    AtomicInteger primeCount = new AtomicInteger(0);
    CountDownLatch latch = new CountDownLatch(1);
    // 使用单线程调度器,内存占用最低
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    Runnable pollTask = () -> {
        int number = supplierMethod().get();
        if (isPrime(number)) {
            System.out.println("Found prime: " + number);
            if (primeCount.incrementAndGet() >= 500) {
                latch.countDown();
                scheduler.shutdown(); // 条件满足后立即停止调度
            }
        }
    };

    // 立即执行第一次轮询,之后每隔3秒重复
    scheduler.scheduleAtFixedRate(pollTask, 0, 3, TimeUnit.SECONDS);

    // 等待超时或条件触发
    if (!latch.await(1, TimeUnit.HOURS)) {
        scheduler.shutdownNow();
        System.err.println("Timeout exceeded");
    }
}

该方案无任何第三方依赖,线程数固定为1(可根据需求调整),内存开销极低,适合对资源占用敏感的大规模测试场景。

3. 优化响应式方案的内存占用

你之前的响应式实现内存过高,核心问题在于使用了Schedulers.boundedElastic()(会动态创建大量线程)以及冗余的订阅逻辑。优化后的实现如下:

public Mono<Integer> optimizedReactiveAwait(
    Supplier<Integer> supplierMethod,
    Duration pollInterval,
    Duration timeout
) {
    AtomicInteger primeCount = new AtomicInteger(0);
    return Mono.fromRunnable(() -> {
                int number = supplierMethod().get();
                if (isPrime(number)) {
                    System.out.println("Found prime: " + number);
                    primeCount.incrementAndGet();
                }
            })
            .repeat(() -> primeCount.get() < 500) // 直接基于条件重复
            .delayElement(pollInterval, Schedulers.single()) // 使用单线程调度器
            .last()
            .timeout(timeout)
            .onErrorResume(e -> {
                System.err.println("Timeout exceeded");
                return Mono.empty();
            });
}

static void waitWithOptimizedReactive() {
    Mono<Integer> result = new DifferentAwaitility().optimizedReactiveAwait(
        () -> supplierMethod().get(),
        Duration.ofSeconds(3),
        Duration.ofHours(1)
    );

    Integer finalResult = result.block();
    if (finalResult != null) {
        System.out.println("Result: " + finalResult);
    } else {
        System.err.println("Error: Timeout or other failure occurred");
    }
}

通过使用Schedulers.single()复用单线程、简化重复逻辑,可将响应式方案的内存占用降至与优化后的Awaitility相当的水平。

方案选型建议

  • 若想保留Awaitility的使用习惯:优先选择优化Awaitility线程复用的方案,改动最小,见效最快
  • 若追求极致内存效率:选择Java原生API实现,无依赖,资源占用完全可控
  • 若项目已基于响应式栈:使用优化后的响应式方案,适配现有技术栈

内容的提问来源于stack exchange,提问作者Sal-laS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:14:51