package com.taobao.yugong.common.utils.thread; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; /** * 多线程执行器模板代码,otter中好多地方都写多线程,比较多的都是重复的逻辑代码,抽象一下做个模板把 * * <pre> * 示例代码: * ExecutorTemplate template = new ExecutorTemplate(executor); * ... * try { * for ( ....) { * template.submit(new Runnable() {}) * } * * List<?> result = template.waitForResult(); * // do result * } finally { * template.clear(); * } * * 注意:该模板工程,不支持多业务并发调用,会出现数据混乱 * </pre> * * @author agapple 2013-2-26 下午10:46:43 */ public class ExecutorTemplate { private volatile ExecutorCompletionService comletions = null; private volatile List<Future> futures = null; public ExecutorTemplate(ThreadPoolExecutor executor){ futures = Collections.synchronizedList(new ArrayList<Future>()); comletions = new ExecutorCompletionService(executor); } public void submit(Runnable task) { Future future = comletions.submit(task, null); futures.add(future); check(future); } public void submit(Callable<Exception> task) { Future future = comletions.submit(task); futures.add(future); check(future); } private void check(Future future) { if (future.isDone()) { // 立即判断一次,因为使用了CallerRun可能当场跑出结果,针对有异常时快速响应,而不是等跑完所有的才抛异常 try { future.get(); } catch (Throwable e) { // 取消完之后立马退出 cacelAllFutures(); throw new RuntimeException(e); } } } public synchronized List<?> waitForResult() { List result = new ArrayList(); RuntimeException exception = null; // 开始处理结果 int index = 0; while (index < futures.size()) { // 循环处理发出去的所有任务 try { Future future = comletions.take();// 它也可能被打断 result.add(future.get()); } catch (Throwable e) { exception = new RuntimeException(e); // 如何一个future出现了异常,就退出 break; } index++; } if (exception != null) { // 小于代表有错误,需要对未完成的记录进行cancel操作,对已完成的结果进行收集,做重复录入过滤记录 cacelAllFutures(); throw exception; } else { return result; } } public void cacelAllFutures() { for (Future future : futures) { if (!future.isDone() && !future.isCancelled()) { future.cancel(true); } } } public void clear() { futures.clear(); } }