I am trying to stop a long running method after 10 seconds of execution, so far i followed the timer instructions on baeldung.
https://www.baeldung.com/java-stop-execution-after-certain-time#1-using-a-timer
When the method is a simple call to a thread sleep it works, but when I call my function with sub methods it doesn’t stop.
My implementation looks like this:
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"); } } }
And the way I am calling this execution is throught the executeTimedExperiment method
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); }
The executeExperiment method is the long running and I marked it with InterruptedException but the compiler tells me the exception is never throw.
What happens now when I execute it is that it runs normally without stoppping.
I am not sure if I need to add InterruptedException to the submethods or something else, but I would like to not touch the submethods if possible.
Thanks in advance.
Advertisement
Answer
You will need to do more than add throws InterruptedException
to all of those ‘submethods’ (and your own methods). The body of each of those methods must be altered to properly respond to interrupts.
It is not possible to arbitrarily stop running code. Interrupts are cooperative—they only mean something if the thread being interrupted pays attention to them.
Your run()
method does this properly: by placing the entire loop inside a try/catch, any InterruptedException will cause the loop to terminate and thus the thread will terminate.
But the methods it calls must do the same thing. Your run
method calls executeExperiment
, which does this:
String[] files = getFiles(carpeta);
I don’t know how long that method takes, but if it takes any significant amount of time at all (more than a fraction of a second), it needs to be capable of throwing InterruptedException in the middle of the file reading.
executeExperiment also calls executeCase
, which calls the ‘submethods’ readDataToGraph, ExactSolution, and addNewCase. As above, each of those methods which takes more than a fraction of a second needs to respond to an interrupt by throw InterruptedException. So, I’m afraid you will need to modify them.
An example would be:
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); } }