Search code examples
javaasynchronoustimeoutrunnable

How can I implement a Runnable with timeout?


I currently have a rather simple SSL server/client project that involves a standard Java backend and an Android frontend. I wanted to try to read a response from the server after I send data with the client. However, I encountered a little problem. The server doesn't always respond, so I had to somehow try to get a response in an asynchronous way. (because the read() method is a blocking one) After some messing around I found a working solution, but it seems so weird to me, like Im doing something that is potentially "dangerous". The first thing I did was to create a new Runnable and Thread object:

                    //  "reader" is of type "BufferedReader"             

                    Runnable receiveResponse = new Runnable() {
                        boolean stop = false;
                        @Override
                        public void run() {
                            try {
                                new Timer().schedule(new TimerTask() {
                                    @Override
                                    public void run() {
                                        stop = true;
                                    }
                                }, 5000);
                                char receive;
                                StringBuilder responseBuilder = new StringBuilder();
                                while (!stop && ((receive = (char) reader.read()) != END_OF_STREAM_CHAR)) {
                                    responseBuilder.append(receive);
                                }
                                // If the server responds in time I can continue processing the response etc.
                            } catch (Exception ex) {
                                // Handle exception ...
                            }
                        }
                    };
                    Thread thread = new Thread(receiveResponse);
                    thread.start();

As you can see I used a boolean "stop" (that I set to true after 5 seconds) inside the while loop as an additional condition. The "reader.read()" method is a blocking one, so if I wouldn't implement some type of stopping the thread this method would block an infinite amount of time, if the server doesn't respond. Thats why I tried using a Timer that simply sets the "stop" boolean to true.

I know this isn't the best solution and at some point I would redesign this entire thing altogether, but I still wonder whether or not the thing I'm doing right now is okay or not. It certainly works, but that sadly doesn't mean anything.


Solution

  • You are right, such approach with starting one more thread is not perfect. It would be hard to support such code.

    I'd suggest to use a Thread Executor instead. Your code could look as follows:

    Runnable receiveResponse = new Runnable() {
        ...
    };
    
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<?> future = executor.submit(receiveResponse);
    
    try {
        Object result = future.get(5000, TimeUnit.MILLISECONDS);
        System.out.println("Completed successfully");
    } catch (InterruptedException e) {
        ...
    } catch (ExecutionException e) {
        ...
    } catch (TimeoutException e) {
        System.out.println("Timed out. Cancelling the runnable...");
        future.cancel(true);
    }
    
    executor.shutdown();