Clean way to limit the execution of a java code block by a timeout



java

Sometimes you want to limit the execution of a java code block by a timeout.

This is a class I created, if a timeout is reached before the termination of the code block execution, a TimeOutException will be thrown.

import java.util.concurrent.Callable;  
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;

/**
 * @author amgohan
 *
 */
public class TimeLimitedTaskExecutor {

    private final ExecutorService executor;

    public TimeLimitedTaskExecutor(final int threadPoolSize) {

        if (threadPoolSize < 1) {
            throw new IllegalArgumentException("threadPoolSize must be >= 1");
        }
        this.executor = Executors.newFixedThreadPool(threadPoolSize);
    }

    public <T> T run(
        final Callable<T> callable,
        final long timeout,
        final TimeUnit timeUnit)
        throws Exception {

        final Future<T> future = this.executor.submit(callable);
        try {
            return future.get(timeout, timeUnit);
        } catch (final TimeoutException e) {
            future.cancel(true);
            throw e;
        }
    }

    public void shutdown()
        throws Exception {

        this.executor.shutdownNow();
    }

}

The following unit test shows how to use the TimeLimitedTaskExecutor :

import java.util.concurrent.Callable;  
import java.util.concurrent.TimeUnit;  
import java.util.concurrent.TimeoutException;

import org.junit.Assert;  
import org.junit.Test;

/**
 * @author amgohan
 *
 */
public class TimeLimitedTaskExecutorTest {

    private final static int SLEEP_TIME_MILLIS = 2000;

    private final static int TIMEOUT_MILLIS = 1000;

    @Test(expected = TimeoutException.class)
    public void timeExecutionExceedTimeoutTest()
        throws Exception {

        final TimeLimitedTaskExecutor timeLimitedTaskExecutor = new TimeLimitedTaskExecutor(1);

        timeLimitedTaskExecutor.run(new Callable<Boolean>() {

            @Override
            public Boolean call()
                throws Exception {

                Thread.sleep(SLEEP_TIME_MILLIS);
                return null;
            }
        }, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    }

    @Test
    public void successExecutionTest()
        throws Exception {

        final TimeLimitedTaskExecutor timeLimitedTaskExecutor = new TimeLimitedTaskExecutor(1);

        final Boolean result = timeLimitedTaskExecutor.run(new Callable<Boolean>() {

            @Override
            public Boolean call()
                throws Exception {

                return Boolean.TRUE;
            }
        }, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);

        Assert.assertTrue(result);
    }
}



comments powered by Disqus