简体   繁体   English

实施TimeoutTask的最佳方法

[英]Best way to implement TimeoutTask

I'm trying to implement a TimeoutTask which will terminate after a given timeout. 我正在尝试实现一个TimeoutTask ,它将在给定的超时后终止。 Here is what I have: 这是我所拥有的:

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);  
    }
}

It is working and I can see the message on timeout if there is no input given. 它正在工作,如果没有输入,我可以看到超时消息。 However the process doesn't get terminated. 但是,该过程不会终止。 Following is the screenshot from Eclipse's console, see the highlighted portion: 以下是Eclipse控制台的屏幕截图,请参见突出显示的部分:

在此处输入图片说明

When I am giving any input the process terminated immediately. 当我提供任何输入时,该过程将立即终止。 I am calling the FutureTask#cancel from the catch block also from finally block I am asking to shutdown the service by making a call to ExecutorService#shoutDownNow and I can see it is printing that the finally get called. 我从catch块也从finally块调用FutureTask#cancel ,我要求通过调用ExecutorService#shoutDownNow来关闭服务,我可以看到它正在打印finally调用。

  • How can I stop the process being executed any further in case of timeout? 如果超时,如何停止正在执行的进程?
  • Is there any better approach to achieve this? 有没有更好的方法来实现这一目标?

I am using Java 8 . 我正在使用Java 8

Reference: 参考:

Update 更新

In the answer of Marko Topolnik said that the cause is of non-interrupted Java IO; Marko Topolnik的回答中,原因是Java IO不受干扰。 so I change the Callable as: 所以我将Callable更改为:

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

    }
    return i;
};

For this case the same thing happened. 对于这种情况,发生了同样的事情。

Note: The Callable is just a sample. 注意: Callable只是一个示例。

You call 你打电话

String str = consoleReader.readLine();

which means you are using the classic, blocking, non-interruptible Java IO. 这意味着您正在使用经典的,阻塞的, 不间断的 Java IO。 The method keeps blocking even after the timeout and shutdownNow() can't touch it, either, because it also just tries to interrupt the thread. 该方法即使在超时和shutdownNow()也无法触及它之后仍然保持阻塞,因为它也只是试图中断线程。

BTW I have run your code and the output shows "Finally called". 顺便说一句,我已经运行了您的代码,输出显示为“最终调用”。

Update 更新

Your updated Callable is just as non-interruptible as the original one. 您更新后的Callable与原始Callable一样不间断。 You must either call a method which declares to throw InterruptedException (such as Thread.sleep() ) or check Thread.interrupted() yourself in the loop. 您必须调用一个声明抛出InterruptedException的方法(例如Thread.sleep() ),或者自己在循环中检查Thread.interrupted()

The issue you need to solve is that System.in.read() does not response to interrupts. 您需要解决的问题是System.in.read()不响应中断。 See how to bypass this in Heinz M. Kabutz newsletter Heinz M. Kabutz通讯中了解如何绕过此操作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM