Java concurrency线程池之Callable和Future_动力节点Java学院整理
callable 和 future 简介
callable 和 future 是比较有趣的一对组合。当我们需要获取线程的执行结果时,就需要用到它们。callable用于产生结果,future用于获取结果。
1. callable
callable 是一个接口,它只包含一个call()方法。callable是一个返回结果并且可能抛出异常的任务。
为了便于理解,我们可以将callable比作一个runnable接口,而callable的call()方法则类似于runnable的run()方法。
callable的源码如下:
public interface callable<v> { v call() throws exception; }
说明:从中我们可以看出callable支持泛型。
2. future
future 是一个接口。它用于表示异步计算的结果。提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。
future的源码如下:
public interface future<v> { // 试图取消对此任务的执行。 boolean cancel(boolean mayinterruptifrunning) // 如果在任务正常完成前将其取消,则返回 true。 boolean iscancelled() // 如果任务已完成,则返回 true。 boolean isdone() // 如有必要,等待计算完成,然后获取其结果。 v get() throws interruptedexception, executionexception; // 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 v get(long timeout, timeunit unit) throws interruptedexception, executionexception, timeoutexception; }
说明: future用于表示异步计算的结果。它的实现类是futuretask,在讲解futuretask之前,我们先看看callable, future, futuretask它们之间的关系图,如下:
说明:
(01) runnablefuture是一个接口,它继承了runnable和future这两个接口。runnablefuture的源码如下:
public interface runnablefuture<v> extends runnable, future<v> { void run(); }
(02) futuretask实现了runnablefuture接口。所以,我们也说它实现了future接口。
示例和源码分析(基于jdk1.7.0_40)
我们先通过一个示例看看callable和future的基本用法,然后再分析示例的实现原理。
import java.util.concurrent.callable; import java.util.concurrent.future; import java.util.concurrent.executors; import java.util.concurrent.executorservice; import java.util.concurrent.executionexception; class mycallable implements callable { @override public integer call() throws exception { int sum = 0; // 执行任务 for (int i=0; i<100; i++) sum += i; //return sum; return integer.valueof(sum); } } public class callabletest1 { public static void main(string[] args) throws executionexception, interruptedexception{ //创建一个线程池 executorservice pool = executors.newsinglethreadexecutor(); //创建有返回值的任务 callable c1 = new mycallable(); //执行任务并获取future对象 future f1 = pool.submit(c1); // 输出结果 system.out.println(f1.get()); //关闭线程池 pool.shutdown(); } }
运行结果:
4950
结果说明:
在主线程main中,通过newsinglethreadexecutor()新建一个线程池。接着创建callable对象c1,然后再通过pool.submit(c1)将c1提交到线程池中进行处理,并且将返回的结果保存到future对象f1中。然后,我们通过f1.get()获取callable中保存的结果;最后通过pool.shutdown()关闭线程池。
1. submit()
submit()在java/util/concurrent/abstractexecutorservice.java中实现,它的源码如下:
public <t> future<t> submit(callable<t> task) { if (task == null) throw new nullpointerexception(); // 创建一个runnablefuture对象 runnablefuture<t> ftask = newtaskfor(task); // 执行“任务ftask” execute(ftask); // 返回“ftask” return ftask; }
说明:submit()通过newtaskfor(task)创建了runnablefuture对象ftask。它的源码如下:
protected <t> runnablefuture<t> newtaskfor(callable<t> callable) { return new futuretask<t>(callable); }
2. futuretask的构造函数
futuretask的构造函数如下:
public futuretask(callable<v> callable) { if (callable == null) throw new nullpointerexception(); // callable是一个callable对象 this.callable = callable; // state记录futuretask的状态 this.state = new; // ensure visibility of callable }
3. futuretask的run()方法
我们继续回到submit()的源码中。
在newtaskfor()新建一个ftask对象之后,会通过execute(ftask)执行该任务。此时ftask被当作一个runnable对象进行执行,最终会调用到它的run()方法;ftask的run()方法在java/util/concurrent/futuretask.java中实现,源码如下:
public void run() { if (state != new || !unsafe.compareandswapobject(this, runneroffset, null, thread.currentthread())) return; try { // 将callable对象赋值给c。 callable<v> c = callable; if (c != null && state == new) { v result; boolean ran; try { // 执行callable的call()方法,并保存结果到result中。 result = c.call(); ran = true; } catch (throwable ex) { result = null; ran = false; setexception(ex); } // 如果运行成功,则将result保存 if (ran) set(result); } } finally { runner = null; // 设置“state状态标记” int s = state; if (s >= interrupting) handlepossiblecancellationinterrupt(s); } }
说明:run()中会执行callable对象的call()方法,并且最终将结果保存到result中,并通过set(result)将result保存。
之后调用futuretask的get()方法,返回的就是通过set(result)保存的值。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。