How to timeout a thread

后端 未结 17 1135
时光说笑
时光说笑 2020-11-22 01:01

I want to run a thread for some fixed amount of time. If it is not completed within that time, I want to either kill it, throw some exception, or handle it in some way. How

17条回答
  •  攒了一身酷
    2020-11-22 01:46

    In the solution given by BalusC, the main thread will stay blocked for the timeout period. If you have a thread pool with more than one thread, you will need the same number of additional thread that will be using Future.get(long timeout,TimeUnit unit) blocking call to wait and close the thread if it exceeds the timeout period.

    A generic solution to this problem is to create a ThreadPoolExecutor Decorator that can add the timeout functionality. This Decorator class should create as many threads as ThreadPoolExecutor has, and all these threads should be used only to wait and close the ThreadPoolExecutor.

    The generic class should be implemented like below:

    import java.util.List;
    import java.util.concurrent.*;
    
    public class TimeoutThreadPoolDecorator extends ThreadPoolExecutor {
    
    
        private final ThreadPoolExecutor commandThreadpool;
        private final long timeout;
        private final TimeUnit unit;
    
        public TimeoutThreadPoolDecorator(ThreadPoolExecutor threadpool,
                                          long timeout,
                                          TimeUnit unit ){
            super(  threadpool.getCorePoolSize(),
                    threadpool.getMaximumPoolSize(),
                    threadpool.getKeepAliveTime(TimeUnit.MILLISECONDS),
                    TimeUnit.MILLISECONDS,
                    threadpool.getQueue());
    
            this.commandThreadpool = threadpool;
            this.timeout=timeout;
            this.unit=unit;
        }
    
        @Override
        public void execute(Runnable command) {
            super.execute(() -> {
                Future future = commandThreadpool.submit(command);
                try {
                    future.get(timeout, unit);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } catch (ExecutionException | TimeoutException e) {
                    throw new RejectedExecutionException(e);
                } finally {
                    future.cancel(true);
                }
            });
        }
    
        @Override
        public void setCorePoolSize(int corePoolSize) {
            super.setCorePoolSize(corePoolSize);
            commandThreadpool.setCorePoolSize(corePoolSize);
        }
    
        @Override
        public void setThreadFactory(ThreadFactory threadFactory) {
            super.setThreadFactory(threadFactory);
            commandThreadpool.setThreadFactory(threadFactory);
        }
    
        @Override
        public void setMaximumPoolSize(int maximumPoolSize) {
            super.setMaximumPoolSize(maximumPoolSize);
            commandThreadpool.setMaximumPoolSize(maximumPoolSize);
        }
    
        @Override
        public void setKeepAliveTime(long time, TimeUnit unit) {
            super.setKeepAliveTime(time, unit);
            commandThreadpool.setKeepAliveTime(time, unit);
        }
    
        @Override
        public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
            super.setRejectedExecutionHandler(handler);
            commandThreadpool.setRejectedExecutionHandler(handler);
        }
    
        @Override
        public List shutdownNow() {
            List taskList = super.shutdownNow();
            taskList.addAll(commandThreadpool.shutdownNow());
            return taskList;
        }
    
        @Override
        public void shutdown() {
            super.shutdown();
            commandThreadpool.shutdown();
        }
    }
    

    The above decorator can be used as below:

    import java.util.concurrent.SynchronousQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class Main {
    
        public static void main(String[] args){
    
            long timeout = 2000;
    
            ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 10, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(true));
    
            threadPool = new TimeoutThreadPoolDecorator( threadPool ,
                    timeout,
                    TimeUnit.MILLISECONDS);
    
    
            threadPool.execute(command(1000));
            threadPool.execute(command(1500));
            threadPool.execute(command(2100));
            threadPool.execute(command(2001));
    
            while(threadPool.getActiveCount()>0);
            threadPool.shutdown();
    
    
        }
    
        private static Runnable command(int i) {
    
            return () -> {
                System.out.println("Running Thread:"+Thread.currentThread().getName());
                System.out.println("Starting command with sleep:"+i);
                try {
                    Thread.sleep(i);
                } catch (InterruptedException e) {
                    System.out.println("Thread "+Thread.currentThread().getName()+" with sleep of "+i+" is Interrupted!!!");
                    return;
                }
                System.out.println("Completing Thread "+Thread.currentThread().getName()+" after sleep of "+i);
            };
    
        }
    }
    

提交回复
热议问题