【问题标题】:How do you stop a java method execution with a timer?如何使用计时器停止 Java 方法的执行?
【发布时间】:2022-01-21 16:44:18
【问题描述】:

我试图在执行 10 秒后停止长时间运行的方法,到目前为止,我遵循了 baeldung 上的计时器说明。

https://www.baeldung.com/java-stop-execution-after-certain-time#1-using-a-timer

当方法是对线程睡眠的简单调用时,它可以工作,但是当我使用子方法调用我的函数时,它不会停止。

我的实现如下所示:

 class TimeOutTask extends TimerTask {
        private Thread t;
        private Timer timer;

        TimeOutTask(Thread t, Timer timer){
            this.t = t;
            this.timer = timer;
        }

        public void run() {
            if (t != null && t.isAlive()) {
                t.interrupt();
                timer.cancel();
            }
        }
    }
    class Execution implements Runnable {

        private String carpeta;
        private Experiment exp;

        public Execution(String carpeta, Experiment exp) {
            this.carpeta = carpeta;
            this.exp = exp;
        }

        @Override
        public void run() {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                   exp.executeExperiment(carpeta);
                }
            } catch (InterruptedException e) {
                System.out.println("Fin de ejecución por tiempo");
            }
        }
    }

我调用这个执行的方式是通过 executeTimedExperiment 方法

    public Experiment() {
        this.cases = new ArrayList<>();
    }


    private void executeTimedExperiment(String carpeta){
        Thread t = new Thread(new Execution(carpeta,this));
        Timer timer = new Timer();
        timer.schedule(new TimeOutTask(t, timer), 10000);
        t.start();
    }

    private void executeExperiment(String carpeta) throws InterruptedException {

        String[] files = getFiles(carpeta);
        Arrays.sort(files);

        for (String file : files) {
             executeCase(carpeta, file);
        }

    }

    private boolean executeCase(String carpeta, String file) {

        Graph g = readDataToGraph(carpeta + "/" + file);
        Solution s = new ExactSolutionGenerator().ExactSolution(g);
        addNewCase(file, s);

    }

executeExperiment 方法是长时间运行的,我用 InterruptedException 对其进行了标记,但编译器告诉我永远不会抛出异常。

当我执行它时会发生什么,它可以正常运行而不会停止。

我不确定是否需要将 InterruptedException 添加到子方法或其他内容中,但如果可能的话,我希望不要触及子方法。

提前致谢。

【问题讨论】:

    标签: java multithreading timer interrupt interrupt-handling


    【解决方案1】:

    编译器告诉你这个异常永远不会抛出是因为你的executeExperiment 方法是不可中断的(不像一些阻塞方法,例如Object#wait),所以thread.interrupt 不会让执行这个方法的线程收到InterruptedException

    也许你需要在你的executeExperiment方法中每次迭代files时检查当前线程是否已经中断,如果是,则抛出一个InterruptedException。(但这可能仍然不准确,因为executeCase方法可能会执行很长时间。)

    【讨论】:

    • executeCase 是整个执行过程中最长的方法,我应该检查线程是否被插入到他的方法中?
    • 是的。进一步缩小检查范围。 (作为VGR给出的答案)
    【解决方案2】:

    您需要做的不仅仅是将throws InterruptedException 添加到所有这些“子方法”(以及您自己的方法)。必须更改每个方法的主体以正确响应中断。

    不能任意停止运行代码。中断是合作的——它们只有在被中断的线程注意到它们时才有意义。

    您的 run() 方法正确地做到了这一点:通过将整个循环放在 try/catch 中,任何 InterruptedException 都会导致循环终止,因此线程将终止。

    但是它调用的方法必须做同样的事情。您的run 方法调用executeExperiment,它执行以下操作:

    String[] files = getFiles(carpeta);
    

    我不知道该方法需要多长时间,但如果它需要任何大量时间(超过几分之一秒),它需要能够在文件读取过程中抛出 InterruptedException .

    executeExperiment 还调用 executeCase,后者调用 readDataToGraph、ExactSolution 和 addNewCase 的“子方法”。如上所述,每一个需要超过几分之一秒的方法都需要通过 throw InterruptedException 来响应中断。所以,恐怕你需要修改它们。

    一个例子是:

    private Graph readDataToGraph(String filename)
    throws InterruptedException {
    
        Graph graph = new Graph();
        try (BufferedReader reader = Files.newBufferedReader(Path.of(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                graph.addData(convertDataToGraphEntry(line));
    
                if (Thread.interrupted()) {
                    throw new InterruptedException();
                }
            }
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-14
      • 1970-01-01
      • 2017-05-18
      • 2023-04-11
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      相关资源
      最近更新 更多