How do I call some blocking method with a timeout in Java?

JavaConcurrency

Java Problem Overview


Is there a standard nice way to call a blocking method with a timeout in Java? I want to be able to do:

// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it

if that makes sense.

Thanks.

Java Solutions


Solution 1 - Java

You could use an Executor:

ExecutorService executor = Executors.newCachedThreadPool();
Callable<Object> task = new Callable<Object>() {
   public Object call() {
      return something.blockingMethod();
   }
};
Future<Object> future = executor.submit(task);
try {
   Object result = future.get(5, TimeUnit.SECONDS); 
} catch (TimeoutException ex) {
   // handle the timeout
} catch (InterruptedException e) {
   // handle the interrupts
} catch (ExecutionException e) {
   // handle other exceptions
} finally {
   future.cancel(true); // may or may not desire this
}

If the future.get doesn't return in 5 seconds, it throws a TimeoutException. The timeout can be configured in seconds, minutes, milliseconds or any unit available as a constant in TimeUnit.

See the JavaDoc for more detail.

Solution 2 - Java

You could wrap the call in a FutureTask and use the timeout version of get().

See http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html

Solution 3 - Java

See also Guava's TimeLimiter which uses an Executor behind the scenes.

Solution 4 - Java

It's really great that people try to implement this in so many ways. But the truth is, there is NO way.

Most developers would try to put the blocking call in a different thread and have a future or some timer. BUT there is no way in Java to stop a thread externally, let alone a few very specific cases like the Thread.sleep() and Lock.lockInterruptibly() methods that explicitly handle thread interruption.

So really you have only 3 generic options:

  1. Put your blocking call on a new thread and if the time expires you just move on, leaving that thread hanging. In that case you should make sure the thread is set to be a Daemon thread. This way the thread will not stop your application from terminating.

  2. Use non blocking Java APIs. So for network for example, use NIO2 and use the non blocking methods. For reading from the console use Scanner.hasNext() before blocking etc.

  3. If your blocking call is not an IO, but your logic, then you can repeatedly check for Thread.isInterrupted() to check if it was interrupted externally, and have another thread call thread.interrupt() on the blocking thread

This course about concurrency https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY

really walks through those fundamentals if you really want to understand how it works in Java. It actually talks about those specific limitations and scenarios, and how to go about them in one of the lectures.

I personally try to program without using blocking calls as much as possible. There are toolkits like Vert.x for example that make it really easy and performant to do IO and no IO operations asynchronously and in a non blocking way.

I hope it helps

Solution 5 - Java

There is also an AspectJ solution for that with jcabi-aspects library.

@Timeable(limit = 30, unit = TimeUnit.MINUTES)
public Soup cookSoup() {
  // Cook soup, but for no more than 30 minutes (throw and exception if it takes any longer
}

It can't get more succinct, but you have to depend on AspectJ and introduce it in your build lifecycle, of course.

There is an article explaining it further: Limit Java Method Execution Time

Solution 6 - Java

I'm giving you here the complete code. In place of the method I'm calling, you can use your method:

public class NewTimeout {
	public String simpleMethod() {
		return "simple method";
	}

	public static void main(String[] args) {
		ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
		Callable<Object> task = new Callable<Object>() {
			public Object call() throws InterruptedException {
				Thread.sleep(1100);
				return new NewTimeout().simpleMethod();
			}
		};
		Future<Object> future = executor.submit(task);
		try {
			Object result = future.get(1, TimeUnit.SECONDS); 
			System.out.println(result);
		} catch (TimeoutException ex) {
			System.out.println("Timeout............Timeout...........");
		} catch (InterruptedException e) {
			// handle the interrupts
		} catch (ExecutionException e) {
			// handle other exceptions
		} finally {
			executor.shutdown(); // may or may not desire this
		}
	}
}

Solution 7 - Java

Thread thread = new Thread(new Runnable() {
	public void run() {
		something.blockingMethod();
	}
});
thread.start();
thread.join(2000);
if (thread.isAlive()) {
    thread.stop();
}

Note, that stop is deprecated, better alternative is to set some volatile boolean flag, inside blockingMethod() check it and exit, like this:

import org.junit.*;
import java.util.*;
import junit.framework.TestCase;

public class ThreadTest extends TestCase {
	static class Something implements Runnable {
		private volatile boolean stopRequested;
		private final int steps;
		private final long waitPerStep;
		
		public Something(int steps, long waitPerStep) {
			this.steps = steps;
			this.waitPerStep = waitPerStep;
		}

		@Override
		public void run() {
			blockingMethod();
		}
		
		public void blockingMethod() {
			try {
				for (int i = 0; i < steps && !stopRequested; i++) {
					doALittleBit();
				}
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		}
		
		public void doALittleBit() throws InterruptedException {
			Thread.sleep(waitPerStep);
		}

		public void setStopRequested(boolean stopRequested) {
			this.stopRequested = stopRequested;
		}
	}

    @Test
    public void test() throws InterruptedException {
    	final Something somethingRunnable = new Something(5, 1000);
		Thread thread = new Thread(somethingRunnable);
		thread.start();
		thread.join(2000);
		if (thread.isAlive()) {
			somethingRunnable.setStopRequested(true);
			thread.join(2000);
			assertFalse(thread.isAlive());
		} else {
			fail("Exptected to be alive (5 * 1000 > 2000)");
		}
    }
}

Solution 8 - Java

You need a circuit breaker implementation like the one present in the failsafe project on GitHub.

Solution 9 - Java

Try this. More simple solution. Guarantees that if block didn't execute within the time limit. the process will terminate and throws an exception.

public class TimeoutBlock {

 private final long timeoutMilliSeconds;
	private long timeoutInteval=100;
	
	public TimeoutBlock(long timeoutMilliSeconds){
		this.timeoutMilliSeconds=timeoutMilliSeconds;
	}
	
	public void addBlock(Runnable runnable) throws Throwable{
		long collectIntervals=0;
		Thread timeoutWorker=new Thread(runnable);
		timeoutWorker.start();
		do{ 
			if(collectIntervals>=this.timeoutMilliSeconds){
				timeoutWorker.stop();
				throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
			}
			collectIntervals+=timeoutInteval;           
			Thread.sleep(timeoutInteval);
			
		}while(timeoutWorker.isAlive());
		System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
	}

	/**
	 * @return the timeoutInteval
	 */
	public long getTimeoutInteval() {
		return timeoutInteval;
	}

	/**
	 * @param timeoutInteval the timeoutInteval to set
	 */
	public void setTimeoutInteval(long timeoutInteval) {
		this.timeoutInteval = timeoutInteval;
	}
}

example :

try {
        TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
        Runnable block=new Runnable() {

            @Override
            public void run() {
                //TO DO write block of code 
            }
        };
        
        timeoutBlock.addBlock(block);// execute the runnable block 
        
    } catch (Throwable e) {
        //catch the exception here . Which is block didn't execute within the time limit
    }

Solution 10 - Java

Assume blockingMethod just sleep for some millis:

public void blockingMethod(Object input) {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

My solution is to use wait() and synchronized like this:

public void blockingMethod(final Object input, long millis) {
    final Object lock = new Object();
    new Thread(new Runnable() {

        @Override
        public void run() {
            blockingMethod(input);
            synchronized (lock) {
                lock.notify();
            }
        }
    }).start();
    synchronized (lock) {
        try {
            // Wait for specific millis and release the lock.
            // If blockingMethod is done during waiting time, it will wake
            // me up and give me the lock, and I will finish directly.
            // Otherwise, when the waiting time is over and the
            // blockingMethod is still
            // running, I will reacquire the lock and finish.
            lock.wait(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

So u can replace

something.blockingMethod(input)

to

something.blockingMethod(input, 2000)

Hope it helps.

Solution 11 - Java

In special case of a blocking queue:

Generic java.util.concurrent.SynchronousQueue has a poll method with timeout parameter.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjjujumaView Question on Stackoverflow
Solution 1 - JavaskaffmanView Answer on Stackoverflow
Solution 2 - JavaColin GoudieView Answer on Stackoverflow
Solution 3 - JavaFedericoView Answer on Stackoverflow
Solution 4 - JavaMichael PView Answer on Stackoverflow
Solution 5 - JavagvlasovView Answer on Stackoverflow
Solution 6 - JavaVickyCoolView Answer on Stackoverflow
Solution 7 - JavajnrView Answer on Stackoverflow
Solution 8 - JavaMarco MontelView Answer on Stackoverflow
Solution 9 - JavaNiroshan AbeywickramaView Answer on Stackoverflow
Solution 10 - JavaEuporieView Answer on Stackoverflow
Solution 11 - JavaSam GinrichView Answer on Stackoverflow