在并发处理数据时,一个典型的场景是: 咱们将须要处理的而且很是耗时的任务(例如访问网络IO)交给线程池中的一个线程去处理,咱们当前的线程执行其余的任务,而后当交给线程池的任务执行完成后,咱们再获取执行的结果,对获得的结果进处理,首选会充分利用CPU的多核资源,其次是将会阻塞的任务提早进行提交处理,尽可能减小系统卡顿。(在互联网公司这样网络访问的方式很是常见。) 那么今天咱们来谈一种新的实现方式Future<V>接口Callable<V>接口java
Future<V>接口Callable<V>网络
在Future接口中声明了5个方法,下面依次解释每一个方法的做用:并发
在callable接口中声明了1个方法,call()方法,主要用于执行你的操做,并放回操做后的值。 举个栗子 Future接口和Callable接口常常配合使用,废话很少说,上代码。dom
场景一ide
该场景只是简单的对Future接口和Callable接口进行使用介绍,注意Future接口的get()方法会阻塞,直到线程池中的线程将数据处理完成,才执行后面的操做。函数
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class FutrueTest { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newSingleThreadExecutor();// 单线程,线程池 Future<Long> myFuturetask = executor.submit(new MyFutureTask());// 提交任务 System.out.println("get before"); long result = myFuturetask.get();// 这个地方会阻塞 System.out.println("get after"); System.out.println("get result is " + result); } } class MyFutureTask implements Callable<Long> { [@Override](https://my.oschina.net/u/1162528) public Long call() throws Exception { long result = 1; System.out.println("future task start"); long max = new Random().nextInt(10); for (int i = 1; i <= max; i++)//计算阶乘 { result *= i; } TimeUnit.SECONDS.sleep(10); System.out.println("future task end"); return result; } }
执行结果this
get before future task start future task end get after get result is 720
场景二.net
如今有这样一个需求,就是一会儿提交不少的FutureTask到线程池中,而后我等待处理的结果,此时我要作的是:哪一个FutureTask先处理完成,我就先处理其获得的结果。问题的难度在于:每一个提交到线程池中的FutureTask处理的时间都是不同的,我怎么来的得知那个FutureTask线程先处理完呢? 题外话:仔细想一想:用Join()、CountDownLatch类、CyclicBarrier类是否是感受都不太好实现?考虑了一下直接Runnable接口实现呢,是否是也会很麻烦?!后续会给出对比~ 废话很少说,直接上代码:线程
import java.util.ArrayList; import java.util.Iterator; 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; import java.util.concurrent.TimeUnit; public class FutrueTest { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newCachedThreadPool();// 多个线程的线程池 List<Future<MyResult>> list = new ArrayList<Future<MyResult>>(); for (int i = 1; i <= 6; i++) { list.add(executor.submit(new MyFutureTask(String.valueOf(i))));//提交任务 } System.out.println("do your something"); TimeUnit.SECONDS.sleep(3); int rank = 1; while (true)//一直访问,直到task 列表中的task 为零 { if (list.size() <= 0) { break; } Iterator<Future<MyResult>> iterator = list.iterator(); while (iterator.hasNext())//循环访问task { Future<MyResult> f = iterator.next(); if (f.isDone())//task 是否完成,若是完成则获取值,若是 { MyResult result = f.get(); System.out.println("------------------>my rank is " + rank++ + " future task is " + result.name + " result is " + result.result); iterator.remove(); } } } } } class MyFutureTask implements Callable<MyResult> { private String name; public MyFutureTask(String name) { this.name = name; } [@Override](https://my.oschina.net/u/1162528) public MyResult call() throws Exception { long result = 1; long max = new Random().nextInt(10); for (int i = 1; i <= max; i++)// 计算阶乘 { result *= i; } TimeUnit.SECONDS.sleep(new Random().nextInt(10)); System.out.println(name + " future task result " + result); return new MyResult(name, result); } } class MyResult { String name;//记录任务ID long result;//结果 public MyResult(String name, long result) { super(); this.name = name; this.result = result; } }
运行结果:code
do your something 6 future task result 1 5 future task result 6 ------------------>my rank is 1future task is 5 result is 6 ------------------>my rank is 2future task is 6 result is 1 2 future task result 40320 ------------------>my rank is 3future task is 2 result is 40320 1 future task result 6 4 future task result 720 ------------------>my rank is 4future task is 1 result is 6 ------------------>my rank is 5future task is 4 result is 720 3 future task result 24 ------------------>my rank is 6future task is 3 result is 24
这个地方主要注意这个isDown()这个函数来判断提交的Future任务是否执行完成,若是完成就获取任务结果作后续的处理。 可是咱们发现,存在一个问题就是:并无真的像我想一想的那样,哪一个任务先执行完,我就先处理哪一个,难道就真的没有办法了么?! 看下面代码:
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class FutrueTest { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newCachedThreadPool();// 多个线程的线程池 CompletionService<MyResult> completionService = new ExecutorCompletionService<MyResult>(executor);//主要是这个类 for (int i = 1; i <= 6; i++) { completionService.submit(new MyFutureTask(String.valueOf(i)));// 提交任务 } System.out.println("do your something"); TimeUnit.SECONDS.sleep(3);//休眠,也能够不休眠 int rank = 0; for (int i = 1; i <= 6; i++) { MyResult result = completionService.take().get();// 会阻塞哦 System.out.println("------------------>my rank is " + rank++ + " future task is " + result.name + " result is " + result.result); } } } class MyFutureTask implements Callable<MyResult> { private String name; public MyFutureTask(String name) { this.name = name; } [@Override](https://my.oschina.net/u/1162528) public MyResult call() throws Exception { long result = 1; long max = new Random().nextInt(10); for (int i = 1; i <= max; i++)// 计算阶乘 { result *= i; } TimeUnit.SECONDS.sleep(new Random().nextInt(10)); System.out.println(name + " future task result " + result); return new MyResult(name, result); } } class MyResult { String name;// 记录任务ID long result;// 结果 public MyResult(String name, long result) { super(); this.name = name; this.result = result; } }
运行结果
do your something 3 future task result 24 1 future task result 6 4 future task result 1 ------------------>my rank is 0 future task is 3 result is 24 ------------------>my rank is 1 future task is 1 result is 6 ------------------>my rank is 2 future task is 4 result is 1 5 future task result 720 6 future task result 40320 ------------------>my rank is 3 future task is 5 result is 720 ------------------>my rank is 4 future task is 6 result is 40320 2 future task result 2 ------------------>my rank is 5 future task is 2 result is 2 终于获得了咱们想要的结果。
总结 Callable接口和Runnable接口在某些状况下均可以提交一个本身的任务给线程池来执行。
区别在于:
1.Callable接口能够有返回值,而Runnable接口没有。(固然不是绝对的看你怎么实现)
2.Callable接口实现对象经过ExecutorService接口的submit()方法提交到线程池,而Runnable接口实现对象经过Executor接口的execute()方法提交大线程池,固然ExecutorService接口继承Executor接口
至于他们的使用,看场景