【问题标题】:How to implement a timeout for a process in Java?如何在 Java 中为进程实现超时?
【发布时间】:2021-07-03 20:38:57
【问题描述】:

我想为一个进程实现超时,如果它需要超过 X 秒,我希望它停止并执行 return 语句。 在我的实际使用中,我会调用一个 REST API,apiCallController() 代表控制器。

根据我在下面尝试的所有内容,无论如何都会继续执行。

我该如何解决这个问题?

编辑:如果我想要实现的工作,长时间运行的任务将无法完成,这意味着该行

System.out.println("End http/SSH stuff...");

永远不会打印,而这一行

response = "Call successful...";

也不会执行,将响应变量保留为最初初始化的状态

String response = "Call aborted...";

但我仍然需要在超时后返回响应

我一直在这个 Java fiddle 中进行测试(你可以直接粘贴代码):https://javafiddle.leaningtech.com/

谢谢。

import java.util.*;
import java.lang.*;

  public class JavaFiddle
  {
    public static void main(String[] args)
    {
        String response = apiCallController();
        System.out.println(response);
    }
    
    public static String apiCallController() {
        System.out.println("creepy...\n");
        int timeoutSeconds = 2;
        int longRunningTaskDurationSeconds = 5;
        String response = "Call aborted...";

        try 
        {
            new Timer().schedule( 
                new TimerTask() {
                    @Override
                    public void run() {
                        System.out.println("Timeout reached, aborting... (This is where I want everything to stop without killing JVM/Tomcat)");
                        // System.exit(0); This guy shut tomcat down x_X
                        return;
                    }
                }, 
                timeoutSeconds * 1000
            );
            
            System.out.println("Start http/SSH stuff...");
            Thread.sleep(longRunningTaskDurationSeconds * 1000);
            System.out.println("End http/SSH stuff...");
            
            response = "Call successful...";

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

        System.out.println("\npasta...");
        
        return "\n" + response;
    }
    
  }

编辑 2:根据接受的答案,我只是重构了一点:

import java.util.*;
import java.lang.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;

  public class JavaFiddle
  {
    public static void main(String[] args)
    {
        System.out.println("creepy...\n\n");

        String response = apiCallController();
        System.out.println(response);

        System.out.println("\n\npasta...");
        
    }
    
    public static String apiCallController() {
        String response = "Stuff TIMED out...";
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        Callable<String> r = () -> {
            try {
                System.out.println("Start http/SSH stuff...");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("End http/SSH stuff...");
                return "Stuff COMPLETED successfully...";
            } catch (InterruptedException e) {
                throw e;
            }
        };
        Future<String> task = executor.submit(r);

        try {
            response = task.get(3, TimeUnit.SECONDS);
        } catch(InterruptedException | TimeoutException e) {
            task.cancel(true);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        // Need to shutdown executor (think of it is master thread here)
        // You may want to control this behaviour outside of this function call
        executor.shutdown();

        return "\n" + response;
    }
    
  }

【问题讨论】:

  • timeout*1000 是什么?
  • 我正在将秒转换为毫秒。
  • 对了,你可以把timeoutSeconds * 1000换成更明显的Duration.ofSeconds( timeoutSeconds ).toMillis()。更好的是,将 timeoutSeconds 的类型更改为名为 timeoutDuration 对象。

标签: java multithreading timer timeout


【解决方案1】:

您的任务在打印到控制台后完成,但您的计时器正在等待更多任务,因此仍在运行,因为它仍在运行,main 函数不会退出。

如果您没有其他任务,您需要cancel您的计时器。

try
        {
            Timer timer = new Timer();
            timer.schedule(
                    new TimerTask() {
                        @Override
                        public void run() {
                            System.out.println("Timeout reached, aborting... (This is where I want everything to stop without killing JVM/Tomcat)");
                        }
                    },
                    timeoutSeconds * 1000
            );

            System.out.println("Start http/SSH stuff...");
            Thread.sleep(longRunningTaskDurationSeconds * 1000);
            System.out.println("End http/SSH stuff...");

            response = "Call successful...";

            timer.cancel();

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

        System.out.println("\npasta...");

        return "\n" + response;

编辑

由于问题已根据实际用例进行了更新,因此我在此处添加了一个编辑以建议该用例的答案(之前的部分可能与现在的问题无关)。

这是我对您问题的解决方案,看看。我已经使用FutureScheduledExecutorService 来实现它。

public static String apiCallController() {
        System.out.println("creepy...\n");
        
        String response = "Call aborted...";

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

        Callable<String> r = () -> {
            try {
                // To mimick the actual call
                TimeUnit.SECONDS.sleep(5);
                System.out.println("call successful...");
                return "Some response";
            } catch (InterruptedException e) {
                System.out.println("Timeout reached, aborting... (This is where I want everything to stop without killing JVM/Tomcat)");
                throw e;
            }
        };

        Future<String> task = executor.submit(r);

        try
        {
            System.out.println("Start http/SSH stuff...");
            
            //Let's just wait for 3 secs for response to arrive
            response = task.get(3, TimeUnit.SECONDS);

            System.out.println("End http/SSH stuff...");

            response = "Call successful...";

        }
        catch(InterruptedException | TimeoutException e)
        {
            // cancelling a task, either it was interrupted (sleep call can be interrupted) or its timeout
            task.cancel(true);
        }catch (ExecutionException e) {
            //Something went wrong horribly
            e.printStackTrace();
        }

        System.out.println("\npasta...");

        // Need to shutdown executor (think of it is master thread here)
        // You may want to control this behaviour outside of this function call
        executor.shutdown();

        return "\n" + response;
    }

【讨论】:

  • 我试图阻止这些行不执行: System.out.println("End http/SSH stuff..."); response = "调用成功...";.他们仍然使用您的解决方案。
  • 请用此信息更新您的问题,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多