简体   繁体   English

如何使用ExecutorService和Futures处理TimeoutException?

[英]How to handle TimeoutException with ExecutorService and Futures?

I have the following example code and let's say that MyCallable("B") takes longer than one second to execute, when the others execute quicker than one second. 我有以下示例代码,假设MyCallable("B")执行时间超过一秒钟,而其他的执行速度则超过一秒钟。 Therefore inside my loop that calls Future.get() , it will throw a TimeoutException . 因此,在调用Future.get()循环中,它将抛出TimeoutException

public static void main(String[] args) {
    ExecutorService es = Executors.newFixedThreadPool(2);

    List<Future<String>> futures = new ArrayList<Future<String>>();

    futures.add(es.submit(new MyCallable("A")));
    futures.add(es.submit(new MyCallable("B")));
    futures.add(es.submit(new MyCallable("C")));
    futures.add(es.submit(new MyCallable("D")));
    futures.add(es.submit(new MyCallable("E")));

    try {
        for(Future<String> f  : futures) {
            try {
                System.out.println("result " + f.get(1, TimeUnit.SECONDS));
            }
            catch (TimeoutException e) {
                // how do I know which MyCallable() has timed out?
            } catch (ExecutionException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }
    finally {
        es.shutdown();
    }
}

As expected each of the MyCallable() instances execute, but for the one that times out I would like to perform some error handling and this requires knowing which Callable is associated with which Future . 正如预期的那样,每个MyCallable()实例都会执行,但是对于超时的那个实例,我想执行一些错误处理,这需要知道哪个Callable与哪个Future关联。

Is there a mechanism for this association or is it up to my Callable to handle all the error processing inside it's call() method? 是否有这种关联的机制,还是由Callable负责处理其call()方法中的所有错误处理?

Seems like you could simply maintain a Map<Future<String>, Callable<String>> instead of a List<Future<String>> and retrieve the original Callable that way. 似乎您可以仅维护Map<Future<String>, Callable<String>>而不是List<Future<String>>然后以这种方式检索原始Callable。

If you want to get really clever, you could do it OO-style and extend ThreadPoolExecutor and create a Future decorator class. 如果您想变得非常聪明,则可以采用OO风格,并扩展ThreadPoolExecutor并创建Future装饰器类。 I think this is probably overkill, but you could do it like this: 我认为这可能是矫kill过正,但是您可以这样做:

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


public class FutureWithCallable<T> implements Future<T> {
    private final Callable<T> callable;
    private final Future<T> wrapped;

    public FutureWithCallable(Future<T> wrapped, Callable<T> callable) {
        this.callable = callable;
        this.wrapped = wrapped;
    }

    public Callable<T> getCallable() {
        return callable;
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return wrapped.cancel(mayInterruptIfRunning);
    }

    @Override
    public T get() throws InterruptedException, ExecutionException {
        return wrapped.get();
    }

    @Override
    public T get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        return wrapped.get(timeout, unit);
    }

    @Override
    public boolean isCancelled() {
        return wrapped.isCancelled();
    }

    @Override
    public boolean isDone() {
        return wrapped.isDone();
    }
}

And then: 接着:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

    public class ExecutorServiceWithCallable extends ThreadPoolExecutor {

        public ExecutorServiceWithCallable(int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue);
        }

        @Override
        public <T> FutureWithCallable submit(Callable<T> callable) {
            Future<T> future = super.submit(callable);
            return new FutureWithCallable<T>(future, callable);
        }

    }

public class TimeoutException extends Exception Exception thrown when a blocking operation times out. 公共类TimeoutException扩展了Exception阻止操作超时时引发的异常。 Blocking operations for which a timeout is specified need a means to indicate that the timeout has occurred. 指定了超时的阻塞操作需要一种手段来指示发生了超时。 For many such operations it is possible to return a value that indicates timeout; 对于许多这样的操作,可以返回一个指示超时的值。 when that is not possible or desirable then TimeoutException should be declared and thrown. 如果不可能或不希望这样做,则应声明并抛出TimeoutException。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM