有人能指导我如何在Java中使用简单的超时吗?基本上,在我的项目中,我正在执行一个语句br.readLine()
,它正在从调制解调器读取响应。但有时调制解调器没有响应。为此,我想添加一个超时。
我正在寻找这样的代码:
try {
String s= br.readLine();
} catch(TimeoutException e) {
System.out.println("Time out has occurred");
}
有人能指导我如何在Java中使用简单的超时吗?基本上,在我的项目中,我正在执行一个语句br.readLine()
,它正在从调制解调器读取响应。但有时调制解调器没有响应。为此,我想添加一个超时。
我正在寻找这样的代码:
try {
String s= br.readLine();
} catch(TimeoutException e) {
System.out.println("Time out has occurred");
}
您要找的内容可以在这里找到。也许有更优雅的方法来完成这个任务,但以下是一种可能的方法:
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();
这些只是草稿,以便您可以获得主要想法。
Future.cancel
需要一个布尔值作为参数。 - msrd0executor.shutdownNow()
后,您可能需要使用 while (true) {try {if (executor.awaitTermination(1, TimeUnit.SECONDS)) break;} catch (InterruptedException ie) {}}
,因为实际停止任务可能需要一些时间。 - Anders Kaseorg现在你可以使用
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
}
编辑: poseidon 正确指出,如果发生超时,上述方法并不会中断正在处理Future任务的底层线程。没有中断,底层线程将继续完成Future任务,而无法知道结果已不再需要。使用中断,底层线程至少可以看到(如果检查),它已被中断,从而允许其优雅地结束处理并退出。
对于JDK中执行阻塞IO的方法,按照惯例,它们实现时会检查调用线程的中断状态(如果为true,则抛出InterruptedException异常)。因此,中断线程可以使它快速退出,即使是在潜在的无限等待情况下,比如读取输入源。
没有进一步的解释,如果我们想在超时时中断底层线程,可以进行如下调整:
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
}
@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
/*
* [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 https://dev59.com/wWIk5IYBdhLWcg3wPL_R
*
* @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";
}
}