如何使用计时器停止 java 方法的执行?

How do you stop a java method execution with a timer?

我试图在执行 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 添加到子方法或其他内容中,但我希望尽可能不要触及子方法。

提前致谢。

编译器告诉你永远不会抛出异常是因为你的 executeExperiment 方法是不可中断的(不像一些阻塞方法,例如 Object#wait),所以 thread.interrupt does not make the thread executing this method receive an InterruptedException.

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

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

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

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

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

String[] files = getFiles(carpeta);

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

executeExperiment 还调用 executeCase,后者调用“子方法”readDataToGraph、ExactSolution 和 addNewCase。如上所述,每一个花费超过几分之一秒的方法都需要通过抛出 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);
    }

}