如果一段代码没有在一定的时间限制内返回,如何导致一段代码在 Java 中超时?



我有以下代码,它连接到服务器,发送请求,然后返回响应。

问题是,如果客户端无法连接到服务器,程序将永远无法通过这一部分

PayLoad payLoadFromServer = client.sendRequest();

我只是想知道防止程序冻结的最佳方法是什么,也就是说,如果客户端无法连接,我想在5秒后超时,并能够在程序中优雅地处理它。注意,我无法编辑客户端类。

public PayLoad queryServer() {
        try (final Client client = new Client("127.0.0.1", "8080")) {
            PayLoad payLoadFromServer = client.sendRequest();
            return payLoadFromServer;
        }
    }

非常感谢!

您应该在Client类中使用java.net.Socket的方法connect(SocketAddress endpoint,int timeout)。这是最好的解决方案,但也可能存在其他解决方案。

我试着快速尝试一下。为客户端类创建一个包装器对象,并使这个新对象可运行。

public class ClientWrapper implements Runnable {
  private final String ip;
  private final String port;
  private Client client;
  Lock lock = new ReentrantLock();
  /**
   * Creates a new instance of ClientWrapper.
   * 
   * @param ip
   * @param port
   */
  public ClientWrapper(String ip, String port) {
    this.ip = ip;
    this.port = port;
  }
  public Lock getLock() {
    return lock;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void run() {
    lock.lock();
    client = new Client(ip, port);
    lock.unlock();
  }
  //create a method to expose client or its methods. 

}

现在使用这个对象的一个实例作为线程,如下所示。

import java.util.concurrent.TimeUnit;
/**
 * @author rbhatt
 */
public class ClientCaller {
  public static void main(String args[]) throws InterruptedException {
    ClientWrapper clientWrapper = new ClientWrapper("127.0.0.1", "8080");
    Thread t = new Thread(clientWrapper);
    t.start();
    boolean ret = clientWrapper.getLock().tryLock(250, TimeUnit.MILLISECONDS);
    if (ret == false) {
      System.out.println("can not acquire lock in 250 milliseconds, kill the thread.");
      t.interrupt();
    } else {
      System.out.println("acquired lock in 250 milliseconds,release lock obtain client!");
      clientWrapper.getLock().unlock();
    }
  }
}

正如您所看到的,您可以在调用者中控制您的超时,而我们无法获得锁,杀死了客户端包装线程。我已经使用了中断,您可以使用volatile变量。您也可以使用executor servicethread pools

注意:我写这段代码只是为了说明这个想法,可以通过多种不同的方式改进代码

我会在客户端代码中添加一个计时器,这样,如果在5秒内没有建立连接,套接字就会关闭。这对外部来说要困难得多。

如果您使用Socket连接到客户端,您可以提供一个SocketFactory,并为它创建的每个Socket设置timout。

换句话说,我可能会使用两个线程。第一个进行实际连接,第二个在第一个超时后触发中断。

这将需要一系列锁,一个用于防止在尝试连接之前发生超时,另一个用于等待尝试

最好使用Timer,这里是网络操作超时的好链接。用Java处理网络超时http://www.javacoffeebreak.com/articles/network_timeouts/

不是最好的主意,但这取决于您的项目逻辑和环境。您可以使用ExecutorService:包装您的方法

import java.util.concurrent.*;
private int threads = 10;
// overide thread count to prevent too many threads to be created
private ExecutorService executor = new ThreadPoolExecutor(0, threads,
        60L, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>());
// if TimeOutException isthrown - then 5 secs is out
public PayLoad sendRequest(long timeout) throws InterruptedException, ExecutionException, TimeoutException {
       return executor.submit(new Callable<PayLoad>() {
            @Override
            public PayLoad call() {
                  // your code implementation of client.sendRequest();
            }
        }).get(timeout, TimeUnit.SECONDS);
 }

我在这里使用了10个线程的缓存线程池。唯一不好的是用另一个线程包装方法的每个调用。不要忘记关闭您的池实现。

相关内容

  • 没有找到相关文章

最新更新