如何在Java方法中设置超时并定期重试

4
我有一个Java方法,可以连接到一个Web服务。有时这个方法连接时间太长。如果它的连接时间超过5秒钟,我想要重启当前程序并尝试3次连接。如果所有连接都失败,则完全终止程序。
到目前为止,我已经编写了以下内容:
        private ConnectionInterface  connectWithTimeout() throws MalformedURLException, Exception {

        ExecutorService executor = Executors.newCachedThreadPool();
        Callable<Object> task = new Callable<Object>() {
            public Object call() throws InterruptedException, MalformedURLException, Exception {
                return connectWithNoTimeout();  //This is the method that takes to long. If this method takes more than 5 seconds, I want to cancel and retry for 3 more times. Then abort completely.
            }
        };
        Future<Object> future = executor.submit(task);
        try {
            Object result = future.get(5, TimeUnit.SECONDS);
        } catch (TimeoutException ex) {

            System.out.println( "Timeout Occured");

        } catch (InterruptedException e) {
          System.out.println( " "InterruptedException Occured");


        } catch (ExecutionException e) {
            System.out.println( ""ExecutionException Occured");


        } finally {

            future.cancel(true); // here the method gets canceled. How do I retry it?
        }
        System.out.println( "Connected !!");
        return connectWithNoTimeout();
}



private ConnectionInterface  connectWithNoTimeout() throws MalformedURLException, Exception {}

1
问题到底是什么?如果我没记错的话,你的 connectWithNoTimeout 方法应该在 5 秒超时后运行。现在你只需要再重复两次就可以了吗? - Amongalen
是的,那是正确的 @Amongalen - Ioanna Katsanou
你尝试过使用for/while循环吗? - Emanuel Graf
@EmanuelGraf 我不确定应该把它放在哪里。 - Ioanna Katsanou
如果您不想自己编写代码,请使用https://github.com/spring-projects/spring-retry。 - Tom Van Rossom
2个回答

3

您的方法已经有了5秒的超时时间。现在您只需要添加一些循环,重复3次即可。您需要一个超时计数器和一个成功尝试后的中断。不确定其他异常发生时您想做什么,也在那里添加了中断。以下代码应该可以完成工作:

private ConnectionInterface  connectWithTimeout() throws MalformedURLException, Exception {
        int repeatCount = 0;

        ExecutorService executor = Executors.newCachedThreadPool();
        Callable<Object> task = new Callable<Object>() {
            public Object call() throws InterruptedException, MalformedURLException, Exception {
                return connectWithNoTimeout();  //This is the method that takes to long. If this method takes more than 5 seconds, I want to cancel and retry for 3 more times. Then abort completely.
            }
        };

        while (repeatCount < 3){
          Future<Object> future = executor.submit(task);
          try {
              Object result = future.get(5, TimeUnit.SECONDS);
              break;

          } catch (TimeoutException ex) {
            repeatCount++;
            System.out.println( "Timeout Occured");

          } catch (InterruptedException e) {
            System.out.println( " "InterruptedException Occured");
            break; 

          } catch (ExecutionException e) {
              System.out.println( "ExecutionException Occured");
            break;    

          } finally {

              future.cancel(true); // here the method gets canceled. How do I retry it?
          }
        }
        System.out.println( "Connected !!");
        return connectWithNoTimeout();
    }

@EmanuelGraf 是的,future.get 会每次阻塞主线程5秒钟。 - Amongalen

2
首先,我会将执行那个长命令的过程放到一个新线程中,这样它就不会阻塞主线程及其UI等。一种方法是:
Thread thr = new Thread() {
            public void run() {
                boolean error =false;
                boolean success=false;
                int time =0;

                try {
                while(tries<3&&!success){
                    //HERE GOES YOUR METHOD (connectWithNoTimeout(); ?)! Make sure to make the boolean "Success" = true if the connection is established
                    while (!error&&time<3) {
                        time++;
                        Thread.sleep(1000);
                       }
 }

 } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }


                }
        };

最初的回答:大部分是手写的,你需要进行修改,复制和粘贴无法起作用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接