1

我正在尝试实现一个TimeoutTask将在给定超时后终止的。这是我所拥有的:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class TimeoutTask {

    private Long timeout;
    private TimeUnit unit;

    public TimeoutTask(Long timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    public <T> T execute(Callable<T> callable) {
        Objects.requireNonNull(timeout, "Timeout");
        Objects.requireNonNull(unit, "Time Unit");
        Objects.requireNonNull(callable, "Callable");

        ExecutorService service = 
                Executors.newFixedThreadPool(1);
        FutureTask<T> task = new FutureTask<T>(callable);
        service.execute(task);

        try {
            return task.get(timeout, unit);
        } catch (InterruptedException | ExecutionException | TimeoutException cause) {
            if(cause instanceof TimeoutException) {
                System.out.println("\nTimeout occured.");
                task.cancel(true);
            }
        } finally {
            System.out.println("Finally called.");
            service.shutdownNow();
        }

        return null;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        Callable<String> callable = () -> {         
            System.out.print("Enter something: ");
            BufferedReader consoleReader = 
                    new BufferedReader(new InputStreamReader(System.in));
            String str = consoleReader.readLine();
            return str;
        };

        TimeoutTask timeoutTask = new TimeoutTask(Long.valueOf(10), TimeUnit.SECONDS);
        timeoutTask.execute(callable);  
    }
}

它正在工作,如果没有给出输入,我可以看到超时消息。但是,该过程不会终止。以下是 Eclipse 控制台的屏幕截图,请参见突出显示的部分:

在此处输入图像描述

当我提供任何输入时,该过程立即终止。我FutureTask#cancel从 catch 块也从 finally 块调用我要求通过调用来关闭服务,ExecutorService#shoutDownNow我可以看到它正在打印 finally 被调用。

  • 如果超时,如何停止正在执行的进程?
  • 有没有更好的方法来实现这一目标?

我正在使用Java 8

参考:

更新

Marko Topolnik的回答中说原因是 Java IO 不中断;所以我将其更改Callable为:

Callable<Long> callable = () -> {           
    long i = 0;
    for(; i <Long.MAX_VALUE;i++){

    }
    return i;
};

对于这种情况,同样的事情发生了。

注意:这Callable只是一个示例。

4

2 回答 2

1

你打电话

String str = consoleReader.readLine();

这意味着您正在使用经典的、阻塞的、不可中断的Java IO。即使在超时之后,该方法也会继续阻塞并且shutdownNow()不能触摸它,因为它也只是试图中断线程。

顺便说一句,我已经运行了您的代码,输出显示“最终调用”。

更新

您的更新Callable与原始更新一样不可中断。您必须调用声明抛出的方法InterruptedException(例如)或在循环中Thread.sleep()检查自己。Thread.interrupted()

于 2014-09-16T08:03:17.967 回答
0

您需要解决的问题是System.in.read()不响应中断。在Heinz M. Kabutz 时事通讯中查看如何绕过此问题

于 2014-09-16T08:11:38.080 回答