Future.get(timeout) does not reliably throw the TimeoutException after the given timeout. Is this normal behavior or can I do something to make this more reliable? This test fails on my machine. However if I sleep for 3000 instead of 2000, it will pass.
public class FutureTimeoutTest {
@Test
public void test() throws
ExecutionException,
InterruptedException {
ExecutorService exec = Executors.newSingleThreadExecutor();
final Callable call = new Callable() {
@Override
public Object call() throws Exception {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return 0;
}
};
final Future future = exec.submit(call);
try {
future.get(1000, TimeUnit.MILLISECONDS);
fail("expected TimeoutException");
} catch (TimeoutException ignore) {
}
}
}
Limitations of the FutureFuture s can not be explicitly completed (setting its value and status). It doesn't have a mechanism to create stages of processing that are chained together. There is no mechanism to run Future s in parallel and after to combined their results together.
Future represents the result of an asynchronous computation. When an asynchronous task is created, a Java Future object is returned.
From the client side, the “read timed out” error happens if the server is taking longer to respond and send information. This could be due to a slow internet connection, or the host could be offline. From the server side, it happens when the server takes a long time to read data compared to the preset timeout.
A Future interface provides methods to check if the computation is complete, to wait for its completion and to retrieve the results of the computation. The result is retrieved using Future's get() method when the computation has completed, and it blocks until it is completed.
There is no reason to expect the test to pass. Given that you submit the task for execution and then wait on its completion, any amount of time could pass before your wait on Future#get()
begins, allowing the task plenty of time to exhaust the sleep duration and complete.
In your case, we can assume that the thread running within the Executor
gets focus while your main thread running through test()
is on hold, despite being in a runnable state. As for the observed difference between stalling the submitted task for two and three seconds, I expect you could find situations where even three seconds is insufficient, depending on what other processes are busy doing on your computer.
@seh is right.
You are expecting what is commonly called "real-time" behavior from Java. This cannot be achieved reliably unless you use real-time libraries in a real-time capable Java distribution running on a real-time operating system.
Just to illustrate, the Java thread implementation in modern JVMs like HotSpot relies on the host operating system's native thread scheduler to decide what threads to run when. Unless the thread scheduler is specifically aware of real-time deadlines and stuff, it is likely to take a "whole of system" view when deciding what threads to run when. If the system is loaded, any particular thread may not get scheduled to run for seconds ... or longer ... after the conditions that prevented it running (e.g. waiting for a timer event) have passed.
Then there is the problem that the Java GC may cause all other threads to block.
If you really need real-time behavior from Java, it is available. For example:
However, you should expect to change your applications to use different APIs to give you real-time behavior.
I have to say, I think the other two answers currently have an unnecessarily low opinion of the Java concurrency classes. They will not give you millisecond accuracy (what "real" real-time applications expect) but they do quite well usually. I've written large scale commercial services using Futures and Executors and they normally worked within 10 milliseconds of the expected times, even under load.
I've run this test both on MacOS 10.6 with Java 1.6 and WinXP w/ Java 1.6.0_22 and both of them work as expected.
I modified the code as follows to test the accuracy:
long time1 = System.nanoTime();
System.out.println("Submitting");
final Future<Object> future = exec.submit(call);
try {
future.get(1000, TimeUnit.MILLISECONDS);
long time2 = System.nanoTime();
System.out.println("No timeout after " +
(time2-time1)/1000000000.0 + " seconds");
fail("expected TimeoutException");
} catch (TimeoutException ignore) {
long time2 = System.nanoTime();
System.out.println("Timed out after " +
(time2-time1)/1000000000.0 + " seconds");
}
finally {
exec.shutdown();
}
In XP this prints "timed out after 1.002598934 seconds" and in MacOS X it prints "timed out after 1.003158 seconds".
If the original poster would describe their OS and JDK version, perhaps we could determine if this is a particular bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With