Reputation: 29806
I'm trying to implement a TimeoutTask
which will terminate after a given timeout. 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:
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.
I am using Java 8.
Reference:
In the answer of Marko Topolnik said that the cause is of non-interrupted Java IO; so I change the Callable
as:
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.
Upvotes: 1
Views: 480
Reputation: 200158
You call
String str = consoleReader.readLine();
which means you are using the classic, blocking, non-interruptible 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.
BTW I have run your code and the output shows "Finally called".
Your updated Callable
is just as non-interruptible as the original one. You must either call a method which declares to throw InterruptedException
(such as Thread.sleep()
) or check Thread.interrupted()
yourself in the loop.
Upvotes: 1
Reputation: 321
The issue you need to solve is that System.in.read()
does not response to interrupts. See how to bypass this in Heinz M. Kabutz newsletter
Upvotes: 0