Reputation: 431
Can anyone guide me on how I can use a simple timeout in java? Basically in my project I'm executing a statement br.readLine()
, which is reading a response from a modem. But sometimes the modem isn't responding. For that purpose I want to add a timeout.
I'm looking for a code like:
try {
String s= br.readLine();
} catch(TimeoutException e) {
System.out.println("Time out has occurred");
}
Upvotes: 43
Views: 177797
Reputation: 199
Nowadays you can use
try {
String s = CompletableFuture.supplyAsync(() -> br.readLine())
.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Time out has occurred");
} catch (InterruptedException | ExecutionException e) {
// Handle
}
EDIT: poseidon correctly points out that in the event of a timeout, the above approach does not interrupt the underlying Thread that is processing the Future's task. Without an interrupt, the underlying Thread will continue to process the Future's task to completion, with no way of knowing that the result is no longer wanted. With an interrupt, the underlying Thread can at least see (if it checks) that it has been interrupted, allowing it to gracefully conclude processing and exit.
For methods in the JDK that do blocking IO, by convention they are implemented such that they check the calling Thread's interrupt status (and throw an InterruptedException if it is true). So, interrupting a Thread can allow it to quickly exit even out of potentially-infinite wait situations, like reading from an input source.
Without further ado, if we want to interrupt the underlying Thread on timeout, we can adjust:
Future<String> future = CompletableFuture.supplyAsync(() -> br.readLine());
try {
String s = future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Time out has occurred");
future.cancel(true);
} catch (InterruptedException | ExecutionException e) {
// Handle
}
EDIT: Still no good, for a more subtle reason: CompletableFuture's cancel method is documented to ignore interrupts. So, we need to get a normal Future. The typical approach is to submit the task to an ExecutorService.
// This would typically be created beforehand and shared broadly
ExecutorService es = Executors.newCachedThreadPool();
Future<String> future = es.submit(() -> br.readLine());
try {
String s = future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Time out has occurred");
future.cancel(true);
} catch (InterruptedException | ExecutionException e) {
// Handle
}
Also note that when Structured Concurrency lands, it will come with a new way of doing this, something like (API pending):
try (var scope = StructuredTaskScope.open(
Joiner.awaitAllSuccessfulOrThrow(),
config -> config.withTimeout(Duration.ofSeconds(1)))
) {
Subtask<String> task = scope.fork(() -> br.readLine());
scope.join();
String s = task.get();
}
Upvotes: 4
Reputation: 21
@Singleton
@AccessTimeout(value=120000)
public class StatusSingletonBean {
private String status;
@Lock(LockType.WRITE)
public void setStatus(String new Status) {
status = newStatus;
}
@Lock(LockType.WRITE)
@AccessTimeout(value=360000)
public void doTediousOperation {
//...
}
}
//The following singleton has a default access timeout value of 60 seconds, specified //using the TimeUnit.SECONDS constant:
@Singleton
@AccessTimeout(value=60, timeUnit=SECONDS)
public class StatusSingletonBean {
//...
}
//The Java EE 6 Tutorial
//https://docs.oracle.com/javaee/6/tutorial/doc/gipvi.html
Upvotes: 0
Reputation: 3688
What you are looking for can be found here. It may exist a more elegant way to accomplish that, but one possible approach is
final Duration timeout = Duration.ofSeconds(30);
ExecutorService executor = Executors.newSingleThreadExecutor();
final Future<String> handler = executor.submit(new Callable() {
@Override
public String call() throws Exception {
return requestDataFromModem();
}
});
try {
handler.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
handler.cancel(true);
}
executor.shutdownNow();
final Duration timeout = Duration.ofSeconds(30);
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
final Future<String> handler = executor.submit(new Callable() {
@Override
public String call() throws Exception {
return requestDataFromModem();
}
});
executor.schedule(new Runnable() {
@Override
public void run(){
handler.cancel(true);
}
}, timeout.toMillis(), TimeUnit.MILLISECONDS);
executor.shutdownNow();
Those are only a draft so that you can get the main idea.
Upvotes: 46
Reputation: 110
The example 1 will not compile. This version of it compiles and runs. It uses lambda features to abbreviate it.
/*
* [RollYourOwnTimeouts.java]
*
* Summary: How to roll your own timeouts.
*
* Copyright: (c) 2016 Roedy Green, Canadian Mind Products, http://mindprod.com
*
* Licence: This software may be copied and used freely for any purpose but military.
* http://mindprod.com/contact/nonmil.html
*
* Requires: JDK 1.8+
*
* Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
*
* Version History:
* 1.0 2016-06-28 initial version
*/
package com.mindprod.example;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.lang.System.*;
/**
* How to roll your own timeouts.
* Based on code at http://stackoverflow.com/questions/19456313/simple-timeout-in-java
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2016-06-28 initial version
* @since 2016-06-28
*/
public class RollYourOwnTimeout
{
private static final long MILLIS_TO_WAIT = 10 * 1000L;
public static void main( final String[] args )
{
final ExecutorService executor = Executors.newSingleThreadExecutor();
// schedule the work
final Future<String> future = executor.submit( RollYourOwnTimeout::requestDataFromWebsite );
try
{
// where we wait for task to complete
final String result = future.get( MILLIS_TO_WAIT, TimeUnit.MILLISECONDS );
out.println( "result: " + result );
}
catch ( TimeoutException e )
{
err.println( "task timed out" );
future.cancel( true /* mayInterruptIfRunning */ );
}
catch ( InterruptedException e )
{
err.println( "task interrupted" );
}
catch ( ExecutionException e )
{
err.println( "task aborted" );
}
executor.shutdownNow();
}
/**
* dummy method to read some data from a website
*/
private static String requestDataFromWebsite()
{
try
{
// force timeout to expire
Thread.sleep( 14_000L );
}
catch ( InterruptedException e )
{
}
return "dummy";
}
}
Upvotes: -1