如何使用计时器停止 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);
}
}
我试图在执行 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);
}
}