ThreadPoolExecutor:当一个任务返回错误时,从invokeAll()取消任务

时间:2014-10-03 18:53:12

标签: java threadpool threadpoolexecutor

我有一个线程池执行程序对批量生成的密钥列表执行相同的操作。所以我使用invokeall()方法处理批处理中的键列表。 usecase是这样的,如果批处理中的任何任务返回错误,则没有必要继续处理其他键。所以

  1. 一旦任务重新调整错误,如何取消批量执行的任务。
  2. 但不影响其他批次的密钥执行。即取消应按批次隔离。
  3. 感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

我不知道如何在没有一点定制的情况下完成这项工作。我能提出的最简单的实现需要:

  • 一个专门的Future实现,基本上是FutureTask的子类,它覆盖setException()方法,以便在任务抛出异常时取消所有其他任务
  • 一个专门的ThreadPoolExecutor实现,它覆盖了invokeAll()以利用自定义的未来

它是这样的:

为自定义的未来:

import java.util.Collection;
import java.util.concurrent.*;

public class MyFutureTask<V> extends FutureTask<V> {
  private Callable<V> task;
  private Collection<Future<V>> allFutures;

  public MyFutureTask(Callable<V> task, Collection<Future<V>> allFutures) {
    super(task);
    this.task = task;
    this.allFutures = allFutures;
  }

  @Override
  protected void setException(Throwable t) {
    super.setException(t);
    synchronized(allFutures) {
      for (Future<V> future: allFutures) {
        if ((future != this) && !future.isDone()) {
          future.cancel(true);
        }
      }
    }
  }
}

用于自定义线程池:

import java.util.*;
import java.util.concurrent.*;

public class MyThreadPool extends ThreadPoolExecutor {
  public MyThreadPool(int size) {
    super(size, size, 1L, TimeUnit.MILLISECONDS,
      new LinkedBlockingQueue<Runnable>());
  }

  @Override
  public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
    throws InterruptedException {
    List<Future<T>> futures = new ArrayList<>(tasks.size());
    for (Callable<T> callable: tasks) {
      futures.add(new MyFutureTask<>(callable, futures));
    }
    for (Future<T> future: futures) {
      execute((MyFutureTask<T>) future);
    }
    for (Future<T> future: futures) {
      try {
        future.get();
      } catch (ExecutionException|CancellationException e) {
        // ignore this exception
      }
    }
    return futures;
  }
}

测试它的代码示例:

import java.util.*;
import java.util.concurrent.*;

public class TestThreadPool {
  public static void main(final String[] args) {
    ExecutorService executor = null;
    try {
      int size = 10;
      executor = new MyThreadPool(size);
      List<Callable<String>> tasks = new ArrayList<>();
      int count=1;
      tasks.add(new MyCallable(count++, false));
      tasks.add(new MyCallable(count++, true));
      List<Future<String>> futures = executor.invokeAll(tasks);
      System.out.println("results:");
      for (int i=0; i<futures.size(); i++) {
        Future<String> f = futures.get(i);
        try {
          System.out.println(f.get());
        } catch (CancellationException e) {
          System.out.println("CancellationException for task " + (i+1) +
            ": " + e.getMessage());
        } catch (ExecutionException e) {
          System.out.println("ExecutionException for task " + (i+1) +
            ": " + e.getMessage());
        }
      }
    } catch(Exception e) {
      e.printStackTrace();
    } finally {
      if (executor != null) executor.shutdownNow();
    }
  }

  public static class MyCallable implements Callable<String> {
    private final int index;
    private final boolean simulateFailure;

    public MyCallable(int index, boolean simulateFailure) {
      this.index = index;
      this.simulateFailure = simulateFailure;
    }

    @Override
    public String call() throws Exception {
      if (simulateFailure) {
        throw new Exception("task " + index + " simulated failure");
      }
      Thread.sleep(2000L);
      return "task " + index + " succesful";
    }
  }
}

最后执行测试的结果,如输出控制台中所示:

results:
CancellationException for task 1: null
ExecutionException for task 2: java.lang.Exception: task 2 simulated failure

答案 1 :(得分:0)

  1. ExecutorService的引用传递给每个任务,如下所示:

    ExecutorService eServ = Executors.newFixedThreadPool(10);
    
    Set<Callable<ReaderThread>> tasks = new HashSet<Callable<ReaderThread>>();
    
    for (int i = 0; i < 10 ; i++)
    {
        tasks.add(new ReaderThread(eServ));
    }
    
    List<Future<ReaderThread>> lt = eServ.invokeAll(tasks);
    
  2. 如果任务错误,则调用shutdownNow()然后它将停止所有任务

    public ReaderThread call() throws Exception 
    {
        try     
        {
            for (int i = 1; i < 50; i++)
            {
                System.out.println("i="+i+"::"+Thread.currentThread());
                Thread.sleep(1000);
    
                if (i == 10 && Thread.currentThread().toString().equals("Thread[pool-1-thread-7,5,main]"))
                {
                    throw new Exception();
                }           
            }
        }
        catch ( Exception exc)
        {
            ex.shutdownNow();       
        }
    
        return this;
    }