java多线程批量执行的时限问题
需求:需要并发执行三个线程,要求在指定的时间内返回结果,如果某个线程超时,则返回为空。
思路:使用ExecutorService的invokeAll(time,timeUint)方法来设置执行时限,该方法返回一个List<Future<T>>,一旦返回后,即取消尚未完成的任务,然后再从list中读取future并调用future.get()方法来获取线程返回的结果,如果future.get()抛出CancellationException 则说明该任务未完成被取消了。
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。返回列表的所有元素的 Future.isDone() 为 true。一旦返回后,即取消尚未完成的任务。注意,可以正常地或通过抛出异常来终止已完成 任务。如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。 参数: tasks - 任务 collection timeout - 最长等待时间 unit - timeout 参数的时间单位 返回: 表示任务的 Future 列表,列表顺序与给定任务列表的迭代器所生成的顺序相同。如果操作未超时,则已完成所有任务。如果确实超时了,则某些任务尚未完成。 抛出: InterruptedException - 如果等待时发生中断,在这种情况下取消尚未完成的任务 NullPointerException - 如果任务或其任意元素或 unit 为 null RejectedExecutionException - 如果所有任务都无法安排执行
public class CallableAndFutureTask { /** * @param args */ public static class MyCallable implements Callable<String>{ private String name; private int age; public MyCallable(String name, int age) { // TODO Auto-generated constructor stub this.name = name; this.age = age; } @Override public String call() throws Exception { // TODO Auto-generated method stub Thread.sleep(new Random().nextInt(4000)); return "name:"+this.name+" "+"age:"+this.age; } } public static void main(String[] args) { //callable 执行任务,future得到任务执行结果 ExecutorService threadPool = Executors.newFixedThreadPool(3); int i = 10; while(i-- > 0){ //创建一个tasks的list List<MyCallable> tasks = new ArrayList<MyCallable>(); tasks.add(new MyCallable("tom", 20)); tasks.add(new MyCallable("john", 30)); tasks.add(new MyCallable("jack", 40));
//用来接收任务执行结果 List<Future<String>> taskResult = null; List<String> result = new ArrayList<String>(); System.out.println("等待结果:"+i); Long s = System.currentTimeMillis(); try { taskResult = threadPool.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } for(int j = 0; j < 3; j ++){ try { result.add(taskResult.get(j).get()); } catch (CancellationException e) { // TODO Auto-generated catch block // e.printStackTrace(); System.out.println(j+"cancled"); }catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("执行时间:"+(System.currentTimeMillis()-s)/1000); if(result.size() == 0){ System.out.println("get no data"); }else{ System.out.println(result); } } } }
和简单的future callable比较,ExecutorService 的submit方法中不能设置时限,只能使用future.get(time,timeUint),但这样一来,再接收结果时就变成了串行,即接收每个任务的结果都需要time的时间,三个任务的执行就变成了3*time,对于单个任务设置超时可以使用这种方式
package com.newTechnologyInJava5; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class CallableAndFutureTask { /** * @param args */ public static class MyCallable implements Callable<String>{ private String name; private int age; public MyCallable(String name, int age) { // TODO Auto-generated constructor stub this.name = name; this.age = age; } @Override public String call() throws Exception { // TODO Auto-generated method stub Thread.sleep(new Random().nextInt(4000)); return "name:"+this.name+" "+"age:"+this.age; } } public static void main(String[] args) { //callable 执行任务,future得到任务执行结果 ExecutorService threadPool = Executors.newFixedThreadPool(3); int i = 10; while(i-- > 0){ Future<String> future1 = threadPool.submit(new MyCallable("tom", 20)); Future<String> future2 = threadPool.submit(new MyCallable("john", 30)); Future<String> future3 = threadPool.submit(new MyCallable("jack", 40)); try { try { result.add(future1.get(3000, TimeUnit.MILLISECONDS)); } catch (TimeoutException e) { // TODO Auto-generated catch block future1.cancel(true); } try { result.add(future2.get(3000, TimeUnit.MILLISECONDS)); } catch (TimeoutException e) { // TODO Auto-generated catch block future2.cancel(true); } try { result.add(future3.get(3000, TimeUnit.MILLISECONDS)); } catch (TimeoutException e) { // TODO Auto-generated catch block future3.cancel(true); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(result.size() == 0){ System.out.println("get no data"); }else{ System.out.println(result); } } } }