42

谁能指导我如何在java中使用简单的超时?基本上在我的项目中,我正在执行一个语句br.readLine(),它正在读取来自调制解调器的响应。但有时调制解调器没有响应。为此,我想添加一个超时。我正在寻找如下代码:

try {
    String s= br.readLine();
} catch(TimeoutException e) {
    System.out.println("Time out has occurred");
}
4

4 回答 4

45

您正在寻找的可以在这里找到。它可能存在一种更优雅的方式来实现这一点,但一种可能的方法是

选项 1(首选):

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

选项 2:

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

这些只是草稿,因此您可以了解主要思想。

于 2013-10-18T18:16:35.017 回答
2

现在你可以使用

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 的方法,按照惯例,它们的实现方式是检查调用线程的中断状态(如果为真则抛出 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
}
于 2020-12-09T23:39:35.507 回答
0
    @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
于 2020-12-18T14:26:59.910 回答
-2

示例 1 将无法编译。它的这个版本编译并运行。它使用 lambda 特性对其进行缩写。

/*
 * [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";
    }

}
于 2016-06-29T06:21:07.340 回答