package com.haogrgr.test.util; import java.util.ArrayList; import java.util.BitSet; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; 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; import java.util.concurrent.atomic.AtomicInteger; public class ConcurrentExec { public static void main(String[] args) throws Exception { final AtomicInteger inc = new AtomicInteger(1); System.out.println(TestUtils.getTimeStr()); List<Future<Integer>> re = ConcurrentExec.exec(new Callable<Integer>() { @Override public Integer call() throws Exception { int s = inc.getAndIncrement(); Thread.sleep(s * 100); return s; } }, 10, 500); System.out.println(TestUtils.getTimeStr()); for (Future<Integer> future : re) { try{ System.out.println(future.get()); }catch(Exception e){ System.out.println(e.getCause()); } } } /** * 并发执行指定任务 * 通过future.isDone轮询任务结果,直到所有任务都完成,或者超时 * * @param task 要并发执行的任务 * @param concurrentCallCount 并发执行线程数 * @param timeoutMillis 超时时间, 小于等于0则永不超时 * @return 完成后的任务结果 */ public static <T> List<Future<T>> exec(Callable<T> task, int concurrentCallCount, int timeoutMillis) { if (task == null) { throw new NullPointerException("任务不能为空 : " + task); } if (concurrentCallCount < 1) { throw new IllegalArgumentException("并行执行次数不能小于1 : " + concurrentCallCount); } List<Future<T>> tasks = new ArrayList<>(concurrentCallCount); final ExecutorService execer = Executors.newFixedThreadPool(concurrentCallCount); try{ for (int i = 0; i < concurrentCallCount; i++) { tasks.add(execer.submit(task)); } int count = 0; BitSet mark = new BitSet(concurrentCallCount); Future<T> unexectued = tasks.get(tasks.size() - 1); long deadline = timeoutMillis > 0 ? System.currentTimeMillis() + timeoutMillis : 0l; //计算超时时间点, 0不超时 while (true) { try { unexectued.get(10, TimeUnit.MILLISECONDS);//先阻塞获取最后一个任务结果, 这里10可以不用写死,弄成衰减 } catch (InterruptedException | ExecutionException | TimeoutException e) { //ignore } for (int i = 0; i < concurrentCallCount && !mark.get(i); i++) { Future<T> future = tasks.get(i); if (future.isDone()) { count++; mark.set(i);//标记为已完成 } else { unexectued = future; } } //结果在超时前成功获取,退出循环 if (count == concurrentCallCount) { break; } //超时 if (deadline != 0 && System.currentTimeMillis() > deadline) { break; } } for (int i = 0; i < concurrentCallCount && !mark.get(i); i++) { tasks.get(i).cancel(true); } }catch(Exception e){ throw new RuntimeException(e); }finally{ execer.shutdownNow(); } return tasks; } }