嗝屁小孩纸 2023-03-19 21:11 采纳率: 80.8%
浏览 25
已结题

诡异的Java代码执行现象

做超时重试这块

        long handleTime = 0;
         boolean checkPass = false;
         for (int i = 0; i < retries; i++) {
            if (handleTime >= timeout) {
               // 超时重试
               rpcRequest.setReSend(Boolean.TRUE);
               log.warn("call service timeout and retry to call [ rms: {}, tms: {} ]", handleTime, timeout);
               log.info("retry counts:{}", retryCounts.incrementAndGet());
            }
            long startTime = System.currentTimeMillis();
            log.info("request call count: {}", count.incrementAndGet());
            log.info("start calling remote service [requestId: {}, serviceMethod: {}]", rpcRequest.getRequestId(), rpcRequest.getMethodName());
            CompletableFuture<RpcResponse> completableFuture = (CompletableFuture<RpcResponse>) rpcClient.sendRequest(rpcRequest);
            try {
               rpcResponse = completableFuture.get(asyncTime, TimeUnit.MILLISECONDS);
            } catch (TimeoutException e) {
               // 忽视 超时引发的异常,自行处理,防止程序中断
               log.warn("recommend that asyncTime [ {} ] should be greater than current task runeTime [ {} ]", asyncTime, System.currentTimeMillis() - startTime);
               continue;
            }

            long endTime = System.currentTimeMillis();
            handleTime = endTime - startTime;

            if (handleTime < timeout) {
               // 没有超时不用再重试
               // 进一步校验包
               checkPass = RpcMessageChecker.check(rpcRequest, rpcResponse);
               if (checkPass) {
                  log.info("success counts:{}", successCounts.incrementAndGet());
                  log.info("client call success [ rms: {}, tms: {} ]", handleTime, timeout);
                  return rpcResponse;
               }
               // 包被 劫持触发 超时重发机制 保护重发
            }
         }
         log.info("client call failed  [ rms: {}, tms: {} ]", handleTime, timeout);
         log.info("fatal counts:{}", fatalCounts.incrementAndGet());
         // 客户端在这里无法探知是否成功收到服务器响应,只能确定该请求包 客户端已经抛弃了
         unprocessedRequests.remove(rpcRequest.getRequestId());
         throw new RetryTimeoutException("The retry call timeout exceeds the threshold, the channel is closed, the thread is interrupted, and an exception is forced to be thrown!");

犹如上面代码,进行调用远程服务时,会出现三种情况,分别为 重试、成功和失败。
这三种现象理应都会调用到 rpcClient.sendRequest(rpcRequest);
但经过大量测试,使用复用线程池执行500个任务,或单独隔离的500个线程去并发测试调用,调用 rpcClient.sendRequest(rpcRequest);次数总大于超时重试、成功和失败的情况总和。
单线程情况下没问题,多线程情况下,每个线程调用的该方法应该都是私有隔离的,而且变量都是局部变量。
多出来的情况按理就是超时才有可能触发调用的,跟服务端应该关系不大。

  • 写回答

1条回答 默认 最新

  • 追cium 2023-03-19 21:13
    关注

    参考GPT和自己的思路:

    这段Java代码看起来并没有什么异常或者明显的错误,但是你遇到的现象确实比较诡异。可能是由于线程池的多线程并发执行导致的问题。建议你检查一下线程池的配置和使用,看看是否有问题;此外,也建议你检查一下网络通信是否正常,包括服务器响应速度和网络稳定性等因素。另外,你可以加入更多的日志输出,帮助你跟踪问题和发现异常。最后,你可以使用调试工具来对程序进行分析,看看程序执行过程中的变量和状态是否符合预期,从而找到问题所在。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 4月6日
  • 已采纳回答 3月29日
  • 修改了问题 3月19日
  • 创建了问题 3月19日

悬赏问题

  • ¥15 vs2022无法联网
  • ¥15 TCP的客户端和服务器的互联
  • ¥15 VB.NET操作免驱摄像头
  • ¥15 笔记本上移动热点开关状态查询
  • ¥85 类鸟群Boids——仿真鸟群避障的相关问题
  • ¥15 CFEDEM自带算例错误,如何解决?
  • ¥15 有没有会使用flac3d软件的家人
  • ¥20 360摄像头无法解绑使用,请教解绑当前账号绑定问题,
  • ¥15 docker实践项目
  • ¥15 利用pthon计算薄膜结构的光导纳