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

基于标识键防止Java方法并发执行的解决方案需求

解决重复POST请求提交问题

核心思路

通过线程安全的请求标识跟踪机制,在请求发起前记录唯一业务标识键,请求执行完成(含异常场景)后移除该键;同一标识的重复请求会被直接拦截,避免向外部API提交重复数据。

实现步骤

  • 用线程安全容器存储正在处理的请求标识,确保多线程环境下的原子性操作
  • 基于业务参数生成唯一请求标识(如消息ID、关键参数组合哈希)
  • 在方法入口校验标识:已存在则拦截重复请求,不存在则标记为处理中
  • 请求结束后无论成功/失败,都清理标识,避免内存泄漏

修改后的代码

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class MessageService { // 替换为你的实际类名
    // 线程安全Map,跟踪正在处理的请求标识
    private static final ConcurrentMap<String, Boolean> PROCESSING_REQUESTS = new ConcurrentHashMap<>();

    public static SendCreateMessageResponse createMessage(String baseUrl, String application, String env, String type, 
                                                         String channel, String modoToken, Message message, 
                                                         ArrayList<ChannelDatum> personalChannels) {
        // 生成唯一请求标识:优先用message的业务ID,无ID则组合关键参数生成
        String requestKey = message.getId(); // 假设message有getId()方法,按需调整
        if (requestKey == null) {
            // 备选方案:组合标题、内容、渠道生成唯一键
            requestKey = String.format("%s_%s_%s", message.getTitle(), message.getBody(), channel);
            // 或用哈希值缩短键长度:requestKey = Integer.toString((message.getTitle() + message.getBody() + channel).hashCode());
        }

        // 原子性检查并标记请求:已存在则拦截
        if (!PROCESSING_REQUESTS.putIfAbsent(requestKey, Boolean.TRUE)) {
            logger.info("拦截重复请求,请求标识:{}", requestKey);
            return null; // 可替换为抛出自定义异常,根据业务需求调整
        }

        PersonalMessageRequest pemr = null;
        OkHttpClient client = new OkHttpClient();
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = null;
        ObjectMapper om = new ObjectMapper();
        Response response = null;

        try {
            pemr = new PersonalMessageRequest();
            PersonalMessage pm = new PersonalMessage();
            pm.setTitle(message.getTitle());
            pm.setBody(message.getBody());
            
            logger.debug("Send message to modo: " + pm);
            pemr.setPersonal_message(pm);

            if(pmr!=null) {
                logger.debug(om.writeValueAsString(pmr));
                body = RequestBody.create(mediaType, om.writeValueAsString(pmr));
            } 
            
            logger.info("Calling URL: "+baseUrl+application+"/"+env+"/"+type+"/channels/"+channel+"/messages");
            logger.trace("Sending data: " + body);
            Request request = new Request.Builder()
              .url(baseUrl+application+"/"+env+"/"+type+"/channels/"+channel+"/messages")
              .method("POST", body)
              .addHeader("accept", "application/vnd.modo.communicate.v2")
              .addHeader("Content-type", "application/json")
              .addHeader("Authorization", "Bearer "+modoToken)
              .build();

            response = client.newCall(request).execute();
            String jsonResponse = response.body().string();
            logger.debug(jsonResponse);
            SendCreateMessageResponse messagesResponse = om.readValue(jsonResponse, SendCreateMessageResponse.class);
            return messagesResponse;
        } catch (IOException e) {
            logger.error("Error creating message", e);
        } finally {
            // 无论请求结果如何,都清理标识,避免内存泄漏
            PROCESSING_REQUESTS.remove(requestKey);
            // 关闭响应体资源
            if(response!=null && response.body()!=null) {
                try {
                    response.body().close();
                } catch (IOException e) {
                    logger.error("Failed to close response body", e);
                }
            }
        }       
        return null;
    }
}

关键细节说明

  • 线程安全保障:使用ConcurrentHashMap的putIfAbsent方法,原子性完成"检查-添加"操作,避免多线程竞态条件
  • 标识唯一性:优先使用业务天然唯一的ID(如消息ID),无ID时组合核心业务参数生成,确保同一业务请求的标识唯一
  • 资源清理:在finally块中移除标识,保证异常场景下也能清理,避免容器内存泄漏
  • 拦截逻辑:重复请求直接返回null,也可抛出DuplicateRequestException等自定义异常,更清晰地反馈给调用方

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:55:41