Java 利用Future异步获取多线程任务结果
Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实现,可以来进行异步计算。
有了Future就可以进行三段式的编程了,1.启动多线程任务2.处理其他事3.收集多线程任务结果。从而实现了非阻塞的任务调用。在途中遇到一个问题,那就是虽然能异步获取结果,但是Future的结果需要通过isdone来判断是否有结果,或者使用get()函数来阻塞式获取执行结果。这样就不能实时跟踪其他线程的结果状态了,所以直接使用get还是要慎用,最好配合isdone来使用。
这里有一种更好的方式来实现对任意一个线程运行完成后的结果都能及时获取的办法:使用CompletionService,它内部添加了阻塞队列,从而获取future中的值,然后根据返回值做对应的处理。一般future使用和CompletionService使用的两个测试案例如下:
package com.yzuzhang.thread; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 多线程执行,异步获取结果 * http://www.cnblogs.com/clarechen/p/4604189.html */ public class AsyncThread { private static List<Future<String>> futureList = new ArrayList<Future<String>>(); public static void main(String[] args) { AsyncThread t = new AsyncThread(); t.generate(3); t.doOtherThings(); t.getResult(futureList); } /** * 生成指定数量的线程,都放入future数组 * * @param threadNum * @param fList */ public void generate(int threadNum) { ExecutorService service = Executors.newFixedThreadPool(threadNum); for (int i = 0; i < threadNum; i++) { Callable<String> job = getJob(i); Future<String> f = service.submit(job); futureList.add(f); } //关闭线程池,不影响线程的执行 service.shutdown(); } /** * other things */ public void doOtherThings() { try { for (int i = 0; i < 3; i++) { System.out.println("Do thing No:" + i); Thread.sleep(new Random().nextInt(5000)); } } catch (InterruptedException e) { e.printStackTrace(); } } /** * 从future中获取线程结果,打印结果 * * @param fList */ public void getResult(List<Future<String>> fList) { ExecutorService service = Executors.newSingleThreadExecutor(); service.execute(getCollectJob(fList)); service.shutdown(); } /** * 生成指定序号的线程对象 * * @param i * @return */ public Callable<String> getJob(final int i) { final int time = new Random().nextInt(10); return new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(1000 * time); return "thread-" + i; } }; } /** * 生成结果收集线程对象 * * @param fList * @return */ public Runnable getCollectJob(final List<Future<String>> fList) { return new Runnable() { @Override public void run() { for (Future<String> future : fList) { try { while (true) { if (future.isDone() && !future.isCancelled()) { System.out.println("Future:" + future + ", Result:" + future.get()); break; } else { System.out.println("休眠100ms..."); Thread.sleep(100); } } } catch (Exception e) { e.printStackTrace(); } } } }; } }
运行结果打印和future放入列表时的顺序一致,为0,1,2:
Do thing No:0 Do thing No:1 Do thing No:2 Future:java.util.concurrent.FutureTask@591c5342, Result:thread-0 Future:java.util.concurrent.FutureTask@529e3fc2, Result:thread-1 Future:java.util.concurrent.FutureTask@136c03ee, Result:thread-2
二、下面是先执行完的线程先处理的方案,使用completionService收集callable结果:
package com.yzuzhang.thread; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.yzuzhang.utils.SleepUtils; /** * Future就可以进行三段式的编程了,从而实现了非阻塞的任务调用 * 1.启动多线程任务 ->处理其他事 ->收集多线程任务结果 */ public class CompletionCallable { //存放处理结果的集合 private static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>(); public static void main(String[] args) { try { completionServiceCount(); } catch (Exception e) { e.printStackTrace(); } } /** * 使用completionService收集callable结果 * @throws ExecutionException * @throws InterruptedException */ public static void completionServiceCount() throws InterruptedException, ExecutionException { ExecutorService threadPool = Executors.newCachedThreadPool(); CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool); int threadNum = 5; for (int i = 0; i < threadNum; i++) { cs.submit(getTask(i)); } int sum = 0, temp = 0; for(int i=0;i<threadNum;i++){ //先执行完的线程,先返回结果 temp = cs.take().get(); sum += map.get(temp); System.out.print(temp + "\t"); } SleepUtils.sleep(1000); System.out.println("Result->" + sum); threadPool.shutdown(); } public static Callable<Integer> getTask(final int no) { final Random rand = new Random(); Callable<Integer> task = new Callable<Integer>() { @Override public Integer call() throws Exception { int time = rand.nextInt(100)*100; map.put(Integer.valueOf(no), time); System.out.println("Thread-"+ no +" sleep :"+ time); Thread.sleep(time); return no; } }; return task; } }
运行结果为最先结束的线程结果先被处理:
Thread-0 sleep :8800 Thread-4 sleep :6800 Thread-1 sleep :4900 Thread-2 sleep :400 Thread-3 sleep :6000 2 1 3 4 0 Result->26900