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

Java如何确保getContent方法同一时间仅一个请求调用Web服务?

这是一个典型的并发请求合并场景,核心是让多个并发请求共享同一个远程调用结果,避免重复发起请求。我给你写一个线程安全的Java实现,完全匹配你的需求:

完整代码实现

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

public class ContentService {
    // 原子引用保存当前正在执行的请求Future,保证多线程下的线程安全
    private final AtomicReference<CompletableFuture<Response>> currentExecutingFuture = new AtomicReference<>();

    public Response getContent() throws MyException {
        while (true) {
            CompletableFuture<Response> existingFuture = currentExecutingFuture.get();
            
            if (existingFuture != null) {
                // 已有请求在处理,直接等待其结果
                try {
                    return existingFuture.join();
                } catch (Exception e) {
                    // 将底层异常转换为自定义异常抛出
                    throw new MyException("等待请求结果失败", e);
                }
            }

            // 没有正在执行的请求,创建新的Future并尝试通过CAS设置到原子引用中
            CompletableFuture<Response> newRequestFuture = new CompletableFuture<>();
            if (currentExecutingFuture.compareAndSet(null, newRequestFuture)) {
                try {
                    // 实际发起Web服务调用
                    Response webResponse = invokeRemoteWebService();
                    // 完成Future,通知所有等待的线程
                    newRequestFuture.complete(webResponse);
                    return webResponse;
                } catch (Exception e) {
                    // 标记Future执行失败,通知所有等待的线程
                    newRequestFuture.completeExceptionally(e);
                    throw new MyException("Web服务调用失败", e);
                } finally {
                    // 无论成功失败,都清空原子引用,让后续请求可以发起新的调用
                    currentExecutingFuture.compareAndSet(newRequestFuture, null);
                }
            }
            // CAS失败意味着其他线程已经抢先发起了请求,回到循环重新获取现有Future
        }
    }

    // 模拟实际的Web服务调用,替换成你的真实调用逻辑(比如RestTemplate、Feign等)
    private Response invokeRemoteWebService() throws Exception {
        // 模拟调用耗时
        Thread.sleep(1000);
        return new Response("从Web服务获取的内容");
    }
}

// 自定义异常类(根据你的实际需求调整)
class MyException extends Exception {
    public MyException(String message, Throwable cause) {
        super(message, cause);
    }
}

// 响应类(根据你的实际需求调整)
class Response {
    private String content;

    public Response(String content) {
        this.content = content;
    }

    // getter、setter等方法
    public String getContent() {
        return content;
    }
}

关键逻辑解释

  • AtomicReference + CAS操作:用AtomicReference保存当前正在执行的请求Future,通过compareAndSet(CAS)原子操作保证多线程下只有一个线程能发起Web服务调用,避免重复请求。
  • CompletableFuture共享结果:所有后续到达的请求会等待第一个请求对应的Future完成,无论成功还是失败,结果都会同步给所有等待的线程。
  • 自动清理机制:在finally块中清空原子引用,确保当前请求处理完成后,新的请求可以正常发起新的Web服务调用,不会一直复用旧的结果。
  • 异常统一处理:无论是Web服务调用本身的异常,还是等待过程中的异常,都会转换为自定义的MyException抛出,保证上层调用的异常一致性。

这个实现完全满足你的需求:第一个请求触发Web服务调用,后续请求等待结果;请求完成(成功/失败)后,所有等待线程同步结果;新的请求到来时会重新发起新的Web服务调用。

内容的提问来源于stack exchange,提问作者Addev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:01:00