Search code examples
javamultithreadingconcurrencyexecutorservicejava.util.concurrent

How to cause a section of code to timeout in Java if it doesn't return with a certain timelimit?


I have the following code which connects to a server, sends a request, then returns the response.

The problem is that if the client can't connect to the server, the program never progresses past this section

PayLoad payLoadFromServer = client.sendRequest();

I am just wondering what the best approach is to prevent the program from freezing, i.e. I want to timeout after say 5 seconds if the client can't connect, and be able to handle that gracefully in the program. Note I can't edit the Client class.

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

            return payLoadFromServer;
        }
    }

Many thanks!


Solution

  • I tried to give it a very quick try. Create a wrapper object for your client class and make this new object runnable.

    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. 
    
    
    }
    

    Now use an instance of this object as a thread like below.

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

    as you can see, you can control your timeout in the caller, and we fail to obtain a lock, kill the client wrapper thread. I have used interrupt, you can use a volatile variable. You can also use a executor service and thread pools etc.

    Note: i have written this code just as an illustration about the idea, one can improve the code in many different ways.